clojure.core/flatten¶
Takes any nested combination of sequential things (lists, vectors, etc.) and returns their contents as a single, flat lazy sequence. (flatten nil) returns an empty sequence.
Examples¶
Note by steveminer¶
(flatten nil) actually returns an empty sequence, not nil. The doc string is fixed in 1.4.
Note by steveminer¶
As shown in the example, flatten will return an empty sequence when given any non-sequential thing. That can sometimes hide a bug.
Here's another version that doesn't have that problem, and is faster as well.
(defn flatten2
"Like `clojure.core/flatten` but better, stronger, faster.
Takes any nested combination of sequential things (lists, vectors,
etc.) and returns their contents as a single, flat, lazy sequence.
If the argument is non-sequential (numbers, maps, strings, nil,
etc.), returns the original argument."
{:static true}
[x]
(letfn [(flat [coll]
(lazy-seq
(when-let [c (seq coll)]
(let [x (first c)]
(if (sequential? x)
(concat (flat x) (flat (rest c)))
(cons x (flat (rest c))))))))]
(if (sequential? x) (flat x) x)))
Note by tonsky¶
Actually, flatten on a vector returns list, not a collection:
user=> (flatten [1 [2 3]])
(1 2 3)
Note by slovic¶
lazy version is much slower than this one:
(defn my-flatten [l]
"free of StackOverflow problem, not lazy and much faster version of flatten."
(loop [l1 l, l2 `()]
(cond
(sequential? (first l1)) (recur (concat (first l1) (rest l1)) l2)
(empty? l1) (reverse l2)
:else (recur (rest l1) (cons (first l1) l2)))))
for complicated construction genereted by:
(defn gen-list-wird [c] (reduce (fn [a b] (list a b)) (map vector (range c) (map str (range c (* 2 c))))))
times are: core/flatten (260 msec) steveminer/flatten (135 msec) my-flatten (2 msec). This version is slower than steveminder`s version for flat and very nested structures with small number of items.
Note by miner¶
For a much faster implementation, use clojure.core.reducers/flatten (introduced in Clojure 1.5).
Note by afhammad¶
To only flatten one level, you can use (mapcat identity coll)
With flatten:
user=> (flatten [[[1]] [[2 3]]]) (1 2 3)
With mapcat identity:
user=> (mapcat identity [[[1]] [[2 3]]]) ([1] [2 3])
Note by moskvo¶
afhammad, i think to flatten one level it may be useful
(apply concat coll)
Note by beluchin¶
does not flatten sets:
user=> (flatten [#{1}])
(#{1})
See also¶
- clojure.core.reducers/flatten
- clojure.core/tree-seq (6)
- clojure.core/sequential? (1)
- clojure.core/mapcat (7)
Content from the matching ClojureDocs page, with authors credited on each contribution.