On Sun, Apr 3, 2011 at 8:45 AM, Roman Sykora <4rt.f...@gmail.com> wrote: > Now, my question is what's the improvement of > >> (defn take-by [f coll] >> (let [fs (map f coll) >> ps (map = fs (rest fs)) >> zs (map #(if %1 %2 sentinel) ps (rest coll))] >> (cons (first coll) (take-while (partial not= sentinel) zs)))) > > over > >> (defn take-by >> [f coll] >> (lazy-seq >> (when-let [s (seq coll)] >> (let [fst (first s) >> value (f fst)] >> (cons fst (take-while #(-> % f (= value)) (rest s))))))) > > Sincerely > Roman
The former is shorter and, IMO, a bit clearer. The lattter though is probably more efficient at runtime. So the answer is really "it depends". The partition-by implementations are even shorter and clearer, of course, but I thought it would be instructive to show a way of implementing that general type of thing (depending on successive elements of a single seq) without using an existing similar function (e.g. partition-by) -- where does the first such function come from? -- and using the basic sequence operations like map, filter, and reduce. The more versatilely you can use those sequence functions to solve problems, the better a Clojure programmer you are, quite frankly. And so ultimately having all the different variations posted here helps everyone reading this thread. There are even a couple of interesting bugs and their fixes in this thread. :) It's also true that the more you look at and understand code like what's in this thread, the more you can get into the "functional" mind-set, making patterns like (map foo x (rest x)) jump quickly to mind (as well as possibly higher-level functions like partition-by) when you see certain kinds of problem (like depending on successive members of a seq). Of course, part of thinking functionally includes thinking how patterns like that can be turned into useful abstractions, too. For example, to get groups of n consecutive elements in general. You could use (map vector x (rest x)) to get all the pairs of successive elements; then again we also have (partition 2 1 x) and the general (partition n 1 x) for this. What about generalizing (map foo x (rest x) (rest (rest x)) ...)? Well, the obvious is (map (partial apply foo) (partition n 1 x))) for this. You could grab this and define it as a function if you find you need it much: (defn map-nextn [f n s] (map (partial apply f) (partition n 1 s))) How would you implement this without partition? One possibility would be (defn map-nextn [f n s] (apply map f (take n (iterate rest s)))) which, interestingly, is actually two characters *shorter*, though I wouldn't say it was clearer. :) Cheers. -- 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