Clojure=> (take-to-first even? [1 1 1 1])
(1 1 1 1)
Clojure=> (take-to-first even? [1 1 1 1 2 3 3 3])
(1 1 1 1 2)
Clojure=> (take-to-first even? [2 2 2 ])
(2)
Additionally, partition-when runs through the seq and partitions it on
demand when a predicate is true. (Leaving the entry where it is seen
to be true in the current partition:
Clojure=> (partition-when even? [1 1 1 2 3 3 3 4 3 3 3 4 3 3 3])
((1 1 1 2) (3 3 3 4) (3 3 3 4) (3 3 3))
Clojure=> (partition-when even? [1 1 1])
((1 1 1))
Clojure=> (partition-when even? [1 1 1 2 3 3 3])
((1 1 1 2) (3 3 3))
Clojure=> (partition-when even? [2 2 2 2])
((2) (2) (2) (2))
These seem to sit aside the current take and partitioning functions
since they are basically looking at an truth value that indicates a
partition or stopping event that we want to capture and cease moving
forward. Here is the source:
(defn take-to-first
"Returns a lazy sequence of successive items from coll up to
and including the point at which it (pred item) returns true.
pred must be free of side-effects."
[pred coll]
(lazy-seq
(when-let [s (seq coll)]
(if-not (pred (first s))
(cons (first s) (take-to pred (rest s)))
(list (first s))))))
(defn partition-when
"Applies f to each value in coll, splitting it each time f returns
true. Returns a lazy seq of lazy seqs."
[f coll]
(when-let [s (seq coll)]
(let [run (take-to-first #(f %) s)
res (drop (count run) s)]
(lazy-seq
(cons run (partition-when f res))))))
I think these could make a good addition to clojure.contrib.seq.
Please let me know if there is an easier way to get this in if you
agree. Also, please let me know if these are the best ways to write
these functions, since I am still a newbie!
user=> (partition-at-fenceposts 1 '(1 2 3 4 5))
((0) (1 2 3 4))
user=> (partition-at-fenceposts 2 '(1 2 3 4 5))
((0 1) (2 3 4))
user=> (partition-at-fenceposts 3 '(1 2 3 4 5))
((0) (1) (2 3 4))
user=> (partitions '(1 2 3))
(((0 1 2)) ((0) (1 2)) ((0 1) (2)) ((0) (1) (2)))
user=> (partitions '(1 2 3 4 5))
(((0 1 2 3 4)) ((0) (1 2 3 4)) ((0 1) (2 3 4)) ((0) (1) (2 3 4)) ((0 1
2) (3 4)) ((0) (1 2) (3 4)) ((0 1) (2) (3 4)) ((0) (1) (2) (3 4)) ((0
1 2 3) (4)) ((0) (1 2 3) (4)) ((0 1) (2 3) (4)) ((0) (1) (2 3) (4))
((0 1 2) (3) (4)) ((0) (1 2) (3) (4)) ((0 1) (2) (3) (4)) ((0) (1) (2)
(3) (4)))
implementation:
(defn take-to-first
"Returns a lazy sequence of successive items from coll up to
and including the point at which it (pred item) returns true.
pred must be free of side-effects."
[pred coll]
(lazy-seq
(when-let [s (seq coll)]
(if-not (pred (first s))
(cons (first s) (take-to-first pred (rest s)))
(list (first s))))))
(defn partition-when
"Applies f to each value in coll, splitting it each time f returns
true. Returns a lazy seq of lazy seqs."
[f coll]
(when-let [s (seq coll)]
(lazy-seq
(let [run (take-to-first f s)
res (drop (count run) s)]
(cons run (partition-when f res))))))
(defn partition-at-fenceposts [b coll]
"Partitions coll at fenceposts corresponding to bits in b that are
set to 1. Returns a lazy seq of lazy seqs."
(let [bits b]
(map #(map first %)
(partition-when
(fn [[i v]] (not (zero? (bit-and (bit-shift-left 1 i)
bits))))
(indexed coll)))))
(defn partitions [coll]
"Returns a lazy seq of possible partitions of coll."
(map #(partition-at-fenceposts % coll) (range (expt 2 (- (count
coll) 1)))))
You might want to take a look at c.c.seq-utils and the clojure cheat
sheet. Both of these already exist. See take-while & partition-by
The cheat sheet can be found here:
http://clojure.org/cheatsheet
partition-by triggers a new partition when the predicate value
*changes*, whereas partition-when triggers a new partition at any
point in the sequence where the predicate is true. take-while takes
all the items up to the point in the sequence where the predicate is
true, where take-to-first does the same but *inclusively*, retaining
the item at which the predicate first becomes true. I'm not sure but I
believe it is not trivial to use partition-by and take-while to
implement either of these.
(defn partitions [xs]
(run-seq (m-partition-where (const [false true]) xs)))
-Per
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@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+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en