15 March 2010

Project Euler Problem 14 in Clojure

This one was fun. I also learned a good lesson the hard way about lazy sequences. When I was playing with the code in the REPL everything worked fine, but I got confused when I hooked everything up and started getting empty lists out of functions. It looked like functions were returning the values pointed to by the atoms before I modified them. I'd read about how lazy sequences don't get evaluated until they are required, but it didn't occur to me that "for" would return immediately, without evaluating anything. In the REPL this doesn't happen of course.

Was also my first look at maps, and the loop macro.

Solves in about 40sec

(defn- next-int [n]
  (if (even? n)
    (/ n 2)
    (+ (* n 3) 1)))

(defn- grow [start-num]
  (let [sequence (atom (list start-num))]
    (loop [head (first @sequence)]
      (let [next (next-int head)]
        (swap! sequence conj next)
        (if (= 1 next)
          @sequence
          (recur next))))))

(defn- measure-sequences []
  (let [counts (atom {})]
    (doall
      (for [start-num (range 1 1000000)]
        (let [sequence (grow start-num)]
          (swap! counts assoc start-num (count sequence)))))
    @counts))

(defn max-map-entry [map]
  (first (sort (comparator #(> (val %1) (val %2))) (seq map))))

(defn solve []
  (first (max-map-entry (measure-sequences))))

Project Euler Problem 13 in Clojure

Really not very interesting

;; defining big list of numbers elided

(defn solve[]
(.substring (str (apply + numbers)) 0 10))

Project Euler Problem 9 in Clojure

Solves in about 16sec. I quite liked the solution though of course the forum posts on the Project Euler site show some much cleverer solutions.

(defn pythagorean-triplet? [a b c]
  (and
    (< a b)
    (< b c)
    (= (+ (* a a) (* b b)) (* c c))))

(defn solve []
  (first
    (for [a (range 1 1000) b (range a 1000) c (range b 1000)
      :when (and
        (pythagorean-triplet? a b c)
        (= 1000 (+ a b c)))]
    (* a b c))))

Project Euler Problem 8 in Clojure

Not very interesting solution, since I use int/string conversions. As a clojure newcomer it feels a bit weird using the Java String API, just because you know its there. Writing functions to wrap the Java String API is probably not idiomatic Clojure, but I think it might be nice to wrap them in macros one day, to make the substring calls look a bit more Clojure-ish.

Solves in about 20msec.

(def bignumber "73167176531330624919......") ;; elided

(defn- calc-offsets []
  (range 0 (- 1000 5)))

(defn- five-digit-list [bigstring offset]
  (let [substr (.substring bigstring offset (+ 5 offset))]
    (map #(Integer/parseInt (str %)) substr)))

(defn- five-digit-lists [bigstring]
  (map #(five-digit-list bigstring %) (calc-offsets)))

(defn solve []
  (apply max (map #(apply * %) (five-digit-lists bignumber))))

11 March 2010

Project Euler Problem 7 in Clojure

Another idea stolen from Ed. This defines a lazy sequence of primes, and holds on to the head, so whichever primes have been realised are memoised, and so are cached for future access.

Takes about 45 seconds to run.

(def primes
  (let [known-primes (atom (list))]
    (for [n (iterate inc 2)
      :when (or
        (= 2 n)
        (not-any? #(zero? (mod n %)) @known-primes))]
    (do
      (swap! known-primes conj n)
      n))))

(defn solve []
  (nth primes 10000))

9 March 2010

Project Euler Problem 6 in Clojure

Wrote a square function so that the result wasn't cast to Double, so I didn't have to mess about with the formatting of the answer.

(defn square [num]
  (* num num))

(defn sum-squares [max]
  (reduce + (map #(square %) (range 1 max))))

(defn square-sum [max]
  (square (apply + (range 1 max))))

(defn solve []
  (- (square-sum 101) (sum-squares 101)))

8 March 2010

Project Euler Problem 5 in Clojure

Not very impressive performance, this brute-force method takes about 30 seconds to run. Could probably be a lot quicker if factors were chosen more intelligently.

(def factors (into () (range 20 3 -1)))

(defn- all-factors [number]
  (if (every? #(zero? (mod number %)) factors)
    number
    (recur (inc number))))

(defn solve[]
  (all-factors 1))