Hi,

Thanks for your review and your improvements (of course also to Justin,
whose improvements are also useful). I'll try to merge them into some
"optimal" solution :)

On Tue, 21 Dec 2010 20:46:56 -0800 (PST)
Benny Tsai <benny.t...@gmail.com> wrote:

> Hi Marek,
> 
> Here's my tweaked version:
> 
> (ns karma
>   (:use [clojure.contrib.duck-streams :only (read-lines)])
>   (:use [clojure.contrib.generic.functor :only (fmap)]))
> 
> (def allowed-nickname "[A-z]{1,16}")
> (def upvote-regexp (re-pattern (format "(%s)\\+\\+" allowed-
> nickname)))
> (def downvote-regexp (re-pattern (format "(%s)\\-\\-" allowed-
> nickname)))
> 
> (defn get-votes [regexp line]
>   (let [nicks (map second (re-seq regexp line))]
>     (frequencies nicks)))
> 
> (defn get-histogram [line]
>   (let [upvotes (get-votes upvote-regexp line)
>       downvotes (fmap - (get-votes downvote-regexp line))]
>     (merge-with + upvotes downvotes)))
> 
> (defn -main [& args]
>   (let [file-name (ffirst args)
>       histograms (map get-histogram (read-lines file-name))
>       histogram (apply merge-with + histograms)
>       non-zero-histogram (remove (comp zero? second) histogram)
>       sorted-by-karma (reverse (sort-by second non-zero-histogram))]
>     (doseq [[nick karma] sorted-by-karma]
>       (println nick karma))))
> 
> (-main *command-line-args*)
> 
> The only non-trivial change is in the way the histogram is created.
> Instead of "updating" an accumulator map while processing each line, I
> create a mini-histogram for each line and then merge them together at
> the end.

Thats very neat. I need to think about it a bit to merge this with
Justins code, which only does one regexp matching per line.

> 'get-votes' is a lot like 'extract-nicks', but leverages the built-in
> 'frequencies' fn to build a histogram of the upvotes/downvotes in a
> line, depending on the regexp passed in:
> 
> karma=> (get-votes upvote-regexp "c++ d++ b++ c--")
> {"c" 1, "d" 1, "b" 1}
> karma=> (get-votes downvote-regexp "c++ d++ b++ c--")
> {"c" 1}
> 
> Given a line, 'get-histogram' uses 'get-votes' to get a histogram of
> the upvotes and a histogram of the downvotes.  It then uses 'fmap' to
> convert the downvotes into negative numbers:
> 
> karma=> (fmap - {"c" 1})
> {"c" -1}

Oh, fmap looks useful, good to know. I 'd probably use a map and
convert it back instead, but this is useful.

> - (first (first ...)) can be shortened into (ffirst ...)

Yeah, I'd usually use `caar' here :)

> - In cases like removing nicks with 0 karma, instead of (filter (not
> pred) ...), I prefer (remove pred ...); I find it a little easier to
> follow that way.

Oh, I didn't know about remove, that's nice.

> - To sort the nicks by karma in descending order, instead of sorting
> by the negation of the karma, I used (reverse (sort-by ...)); again,
> just a subjective thing, makes the intent more clear to me.

It does, but doesn't that make it less lazy? To reverse something, it
needs to evaluate the whole sequence. I yet have to learn how to
deal with lazyness.

> - In the final 'doseq', (first item) and (second item) can be replaced
> by destructuring.

Great! I was wondering whether Clojure supports something like
tuple-unpacking in Python. Does it also support "patterned"
destructuring like:

first, *middle, last = sequence(...)
-or-
first, rest = sequence(...)

The latter could be achived by something like `first+rest', I suppose,
but don't know the "Clojure" name for it.

> Hope you find this useful :)

-- 
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