clojure.core/partition-by¶
Applies f to each value in coll, splitting it each time f returns a new value. Returns a lazy seq of partitions. Returns a stateful transducer when no collection is provided.
Examples¶
Note by Iceland_jack¶
It's worth mentioning that (partition-by identity …) is equivalent to the Data.List.group function in Haskell:
(defn group [coll] (partition-by identity coll))
Which proves to be an interesting idiom:
user=> (apply str
(for [ch (group "fffffffuuuuuuuuuuuu")]
(str (first ch) (count ch))))
⇒ "f7u12"
Note by rauhs¶
Many other programming languages like Kotlin or Haskell define partition slightly different. They partition the given collection into two collections, the first containing all truthy values and the second elements all falsy elements. This function does it:
(defn partition-2
"Partitions the collection into exactly two [[all-truthy] [all-falsy]]
collection."
[pred coll]
(mapv persistent!
(reduce
(fn [[t f] x]
(if (pred x)
[(conj! t x) f]
[t (conj! f x)]))
[(transient []) (transient [])]
coll)))
(partition-2 odd? (range 5))
Note by jcburley¶
I tried this implementation of your Kotlin/Haskell partition, which is simpler but somewhat slower (less than 2x):
(defn partition-3
"Partitions the collection into exactly two [[all-truthy] [all-falsy]]
collection."
[pred coll]
(let [m (group-by pred coll)]
[(m true) (m false)]))
Note by Saikyun¶
A third implementation which in my limited testing in cljs is the fastest so far:
(defn split-by
"Effectively though non-lazily splits the `coll`ection using `pred`,
essentially like `[(filter coll pred) (remove coll pred)]`"
[pred coll]
(let [match (transient [])
no-match (transient [])]
(doseq [v coll]
(if (pred v)
(conj! match v)
(conj! no-match v)))
[(persistent! match) (persistent! no-match)]))
Using simple-benchmark in cljs, these are the results:
[r (range 1000)], (partition-2 odd? r), 1000 runs, 167 msecs
[r (range 1000)], (partition-3 odd? r), 1000 runs, 364 msecs
[r (range 1000)], (split-by odd? r), 1000 runs, 60 msecs
It's worth noting that all implementations of the java-esque partition in this thread are non-lazy.
On big collections where you don't want to realize the whole list, this is the fastest:
Can also be written as:
(taken from: http://blog.jayfields.com/2011/08/clojure-partition-by-split-with-group.html)
Note by zackteo¶
Perhaps this will be of help someone trying to find the regions denoted by partitions
(defn partition-at
"Like partition-by but will start a new run when f returns true"
[f coll]
(lazy-seq
(when-let [s (seq coll)]
(let [run (cons (first s) (take-while #(not (f %)) (rest s)))]
(cons run (partition-at f (drop (count run) s)))))))
See also¶
- clojure.core/partition (6)
- clojure.core/partition-all (3)
- clojure.core/group-by (7)
- clojure.core/dedupe (0)
- clojure.core/sort (1)
- clojure.core/split-with (1)
Content from the matching ClojureDocs page, with authors credited on each contribution.