Skip to content

clojure.core/partition-by

View this page on ClojureDocs

Type: function Added: Clojure 1.2 Examples: 8 Runnable: 3
([f] [f coll])

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

by wilkes on . May have evaluation errors.
by wilkes on . May have evaluation errors.
by belun on . May have evaluation errors.
by martinhynar on . May have evaluation errors.
by vede1 on
by ertugrulcetin on
by artemiy312 on
by johanatan on . May have evaluation errors.

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:

[(filter odd? r) (filter (complement odd?) r)]

Can also be written as:

((juxt filter remove) odd? r)

(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)))))))
(taken from: http://cninja.blogspot.com/2011/02/clojure-partition-at.html#comments)

See also


Content from the matching ClojureDocs page, with authors credited on each contribution.