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

Reply via email to