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.


Reply via email to