Hi Meikel, Nicolas, and Justin,
Thank you for the great feedback! I learned a lot. I was puzzled about
(update-in (update-in)) and after doing that the -> operator makes a
lot of sense. The reduce is clever and fits nicely as well.

I dropped the function that read in the lines of the file and used
read-lines instead. Below is what I put together after the feedback.

Thanks,
Damon

PS- I was mistaken before. The first version was taking over a minute.
This version takes about 15s.

(ns clojure.example.anagrams
  (:require clojure.contrib.duck-streams)
  (:gen-class))

(defn str-sort[string]
  (when string
    (apply str (sort string))))


(defn str-to-lower[string]
  (when string
    (.toLowerCase string)))


(defn anagram-add[anagrams akey word]
  (if (contains? anagrams akey)
    (-> anagrams
      (update-in [akey :count] inc)
      (update-in [akey :words] conj word))
    (assoc anagrams akey {:count 1 :words [word]})))

(def normalise (comp str-to-lower str-sort))

(defn build-anagrams[words]
  (reduce #(anagram-add %1 (normalise %2) %2) {} words))


(defn print-anagram[v]
  (println (str (:count (second v)) " " (first v) ": " (:words (second
v)))))

(defn print-anagrams[ana]
    (doseq [v ana]
          (print-anagram v)))

(defn anagram-key[elem]
    (- (:count (second elem))))


;(def *words* (f-to-seq "/usr/share/dict/web2"))
;(def *anagrams* (sort-by anagram-key (build-anagrams *words*)))
;(print-anagrams (take 10 *anagrams*))

(defn -main[file]
  (time (print-anagrams
          (take 10
                (sort-by anagram-key
                         (build-anagrams
                           (clojure.contrib.duck-streams/read-lines
file)))))))



On Aug 19, 5:41 am, Meikel Brandmeyer <m...@kotka.de> wrote:
> Hi,
>
> here my turn. Comments inline. Hope this helps.
>
> Sincerely
> Meikel
>
> (defn f-to-seq
>   [file]
>   (with-open [rdr (java.io.BufferedReader.
>                     (java.io.FileReader. file))]
>     (doall (line-seq rdr))))
> ; Yes. doall is required here. Alternatively you can wrap the whole
> thing
> ; in the with-open. Then you can process also larger files without
> keeping
> ; all data in memory. YMMV.
>
> (defn str-sort
>   [string]
>   (when string
>     (apply str (sort string))))
> ; One can also skip the when here. Then nil input returns an empty
> string.
> ; Whether that is better depends on the usage of the return value.
> YMMV.
> ; (if (nil? x) x ...) is usually written as (when x ...).
>
> (defn str-to-lower
>   [string]
>   (when string
>     (.toLowerCase string)))
>
> (defn anagram-add
>   [anagrams akey word]
>   (if (contains? anagrams akey)
>     (-> anagrams
>       (update-in [akey :count] inc)
>       (update-in [akey :words] conj word))
>     (assoc anagrams akey {:count 1 :words [word]})))
> ; I would prefer vectors over lists to store stuff. You get nice
> ; things for free, like O(1) appending, O(1) reverse, O(1) random
> ; access, ...
>
> (defn word
>   [s]
>   (first s))
> ; or: (def word first)
> ; not needed for my solution
>
> (def normalise (comp str-to-lower str-sort))
>
> (defn build-anagrams
>   [words]
>   (reduce #(anagram-add %1 (normalise %2) %2) {} words))
> ; Looping with an accumulator, just returning the latter when the
> ; input is exhausted cries for reduce.
>
> (defn print-anagram
>   [v]
>   (println (str (:count (second v)) " " (first v) ": " (:words (second
> v)))))
> ; one could use destructuring to access things.
>
> (defn print-anagram
>   [anagram]
>   (let [[normal-form {:keys [count words]}] anagram]
>     (println (str count " " normal-form ": " words))))
>
> (defn print-anagrams
>   [ana]
>   (doseq [v ana]
>     (print-anagram v)))
> ; more descriptive names would be good, I guess
>
> (defn anagram-key
>   [elem]
>   (- (:count (second elem))))
> ; the minus should take care of the reverse?
>
> (def *words* (f-to-seq "/usr/share/dict/web2"))
> (def *anagrams* (sort-by anagram-key (build-anagrams *words*)))
> (print-anagrams (take 10 *anagrams*))

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to