Hello James, 2013/7/11 James Trunk <james.tr...@gmail.com>: > Hi everyone, I'm new to Clojure and trying to learn my way around the > language. > > I've written a function that sums the frequencies of words starting with the > same letter, however I'm not fully satisfied with the result. I'm striving > for readability and idomaticity, but I fear that my rather limited grasp of > Clojure's core functions and lack of experience with functional programming > are letting me down on both counts. > > (def text (slurp "http://www.ccel.org/ccel/bible/kjv.txt")) > > (defn sum-last-elements [coll] > (reduce + (map last coll))) > > (defn group-first-elements [coll] > (map first coll)) > > (->> text > (re-seq > #"(?:(?:\bm[a|e]n\b)|(?:\bwom[a|e]n\b)|(?:\bchild\b)|(?:\bchildren\b))") > frequencies > (group-by ffirst) > vals > (#(zipmap (map group-first-elements %) (map sum-last-elements %)))) > > Which on that file gives the result: > > {("woman" "women") 663, ("children" "child") 2274, ("men" "man") 5314} > > My questions: > > Is there a way to avoid using ?: everywhere in the regex? > (group-by ffirst) vals - is there a more readable/declarative/idiomatic way > to group by first letter?
you could first (group-by first), then create the final map by calling (distinct) and count > Is there a trick to avoid the ugly looking anonymous function (which I'm > only using to reorder the thread-last argument)? You could use the new as-> macro in clojure 1.5 > Is it idiomatic to extract small functions to give them names (with an eye > to aiding readability) or would most Clojure programmers prefer these to be > anonymous and in-line? depends :-) since your 2 fns are helper fns rather than generically-reusable fns, I would make them private to enforce that : (defn- ...) > Is thread-last the right approach when dealing with nested data-structures > or is list comprehension, or some other approach preferred? The thread-last as you employed it is fine by me. May I suggest alternative implementations ? (def text (slurp "http://www.ccel.org/ccel/bible/kjv.txt")) (let [words (re-seq #"(?:(?:\bm[a|e]n\b)|(?:\bwom[a|e]n\b)|(?:\bchild\b)|(?:\bchildren\b))" text) words-per-initial (vals (group-by first words))] (zipmap (map distinct words-per-initial) (map count words-per-initial))) ;; => {("woman" "women") 663, ("children" "child") 2274, ("men" "man") 5314} or to avoid the intermediary creation of seqs of distincts and seqs of counts: (defn- reduce-initial [m initial initial-words] (assoc m (distinct initial-words) (count initial-words))) (let [words (re-seq #"(?:(?:\bm[a|e]n\b)|(?:\bwom[a|e]n\b)|(?:\bchild\b)|(?:\bchildren\b))" text) words-per-initial (group-by first words)] (reduce-kv reduce-initial {} words-per-initial)) ;; => {("woman" "women") 663, ("children" "child") 2274, ("men" "man") 5314} HTH, -- Laurent -- -- 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 --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.