I've been playing along at home for awhile now, but this example hit close to home -- I've written variations on this code countless times in perl, and figured I'd take a stab at clojuring it while also taking advantage of clojure.contrib.seq-utils's very useful to the matter at hand group-by. I'd understand if the OP doesn't want to use this code due to dependency on non-core or if the variations on making it more general obscure the original intent...
Anyway, my style could use work and the code is littered with comments getting in the way that ask all kinds of questions (I admit, I haven't done my due diligence on finding out if any of these functions exist beyond group-by), but hopefully this variation is helpful to someone or there are answers to my various questions. I'd *love* feedback. Thanks in advance, --Benjy PS. To the original poster, the use of destructuring binds for the arguments to cmpr was rad -- it was something I overlooked when I was doing this in my head over dinner and I was imagining a bunch of inanity involving hash lookups and ifs for falling back to comparing the keys as you'd have to do in other languages. (use '[clojure.contrib.seq-utils :only (group-by)]) ;; is there a better option for this? (defn false-if-zero [t] (if (= t 0) nil t)) ;; the body of this fn should probably be a macro that takes ;; any number of comparisons and or-chain them correctly such that ;; ties cascade to the next comparison and obviates the need for ;; explicit calls to false-if-zero. Does it already exist? (defn cmpr [[key-a val-a] [key-b val-b]] (or (false-if-zero (compare val-b val-a)) (compare key-a key-b))) (defn count-hash-vals [coll] ;; apply hash-map mapcat was the first thing ;; I found that worked here... better options ++welcome. (apply hash-map (mapcat #(let [[k v] %] (list k (count v))) coll))) (defn orderByFreq [coll] (or (keys (sort cmpr (count-hash-vals (group-by identity coll)) ))) ;; as an exercise for the reader, use this call to implement (majority? ...) or (plurality? ...) etc. '()) ;; I don't think this OR short circuiting is idiomatic in clojure, but it sure is handy for "empty list if nil" scenarios. ;; Of course, (empty-list-or-nil ...) reads nice enough... ;; ;; If sort or compare don't do an implicit orcish maneuver ;; ;; or otherwise memoize pieces of this call, performance could ;; ;; suffer; I have not researched this yet. ;; ;; Also, not general: assumes val is countable; val may ;; ;; be comparable but not countable. The above isn't ;; ;; fully general either, of course, but it's better. ;; (defn cmpr [[key-a val-a] [key-b val-b]] ;; (or (false-if-zero (compare (count val-b) (count val-a))) ;; (compare key-a key-b))) ;; (defn orderByFreq [coll] ;; (keys (sort cmpr (group-by identity coll)))) On Thu, Jul 9, 2009 at 6:13 PM, Chouser<chou...@gmail.com> wrote: > > On Thu, Jul 9, 2009 at 7:31 AM, Patrik Fredriksson<patri...@gmail.com> wrote: >> >> My shot at a Clojure implementation, with inspiration from a previous >> post in this group on a similar problem: >> >> (ns step3.pnehm.clojure-orderer >> (:gen-class >> :name step3.pnehm.ClojureOrderer >> :implements [pnehm.Orderer] >> )) > > Nice to see you're not intimidated by gen-class. :-) > >> (defn cmpr [[val1 freq1] [val2 freq2]] >> (let [freq (compare freq2 freq1)] >> (if (not= freq 0) freq (compare val1 val2)))) > > When testing for equality with zero, it's more idiomatic and > sometimes faster to use 'zero?', so perhaps: > > (if-not (zero? freq) freq (compare val1 val2)) > >> (defn -orderByFreq [_ coll] >> (if (empty? coll) () (keys (sort cmpr (count-words coll))))) > > Do you need to return an empty seq? If not, how about: > > (when (seq coll) > (keys (sort cmpr (count-words coll)))) > > --Chouser > > > > --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---