Clojure
Share your thoughts in the 2024 State of Clojure Survey!

Sequences

Clojure defines many algorithms in terms of sequences (seqs). A seq is a logical list, and unlike most Lisps where the list is represented by a concrete, 2-slot structure, Clojure uses the ISeq interface to allow many data structures to provide access to their elements as sequences. The seq function yields an implementation of ISeq appropriate to the collection. Seqs differ from iterators in that they are persistent and immutable, not stateful cursors into a collection. As such, they are useful for much more than foreach - functions can consume and produce seqs, they are thread safe, they can share structure etc.

Most of the sequence library functions are lazy, i.e. functions that return seqs do so incrementally, as they are consumed, and thus consume any seq arguments incrementally as well. Functions returning lazy seqs can be implemented using the lazy-seq macro. See also lazy.

When seq is used on objects that implement Iterable, the resulting sequence is still immutable and persistent, and will represent a single pass across the data. Because that pass might happen lazily, the pass might see changes that happen after seq has been called. Also, if the backing iterator is subject to ConcurrentModificationException, then so too is the resulting seq. When seq is used on native Java arrays, changes to the underlying array will be reflected in the seq - you must copy the source array to get full immutability. That said, there is still a lot of utility to using seq on Iterables and arrays since seqs support multi-pass and lazy algorithms. Robust programs should not mutate arrays or Iterables that have seqs on them.

Many of the functions in the seq library take one or more collections, call seq on them, and then operate on the resulting seq. In other words, many of these functions take collections but operate on their seqs.

The Seq interface

(first coll)

Returns the first item in the collection. Calls seq on its argument. If coll is nil, returns nil.

(rest coll)

Returns a sequence of the items after the first. Calls seq on its argument. If there are no more items, returns a logical sequence for which seq returns nil.

(cons item seq)

Returns a new seq where item is the first element and seq is the rest.

For a discussion of rest vs. next and lazy-seq see lazy.

The Seq library

This is a sampling of the primary sequence functions, grouped broadly by their capabilities. Some functions can be used in different ways and so appear in more than one group. There are many more listed in the API section.

Since Clojure 1.7, Clojure also provides transducers, an alternate model for composable transformations on collections. Transducers decouple the input, processing, and output parts of transformation and allow reuse of transformations in more contexts, such as core.async channels. Many of the sequence functions in the list below will create transducers if the input collection is omitted. See the Transducers page for more details.

Seq in, Seq out

Shorter seq from a longer seq: distinct filter remove for keep keep-indexed
Longer seq from a shorter seq: cons concat lazy-cat mapcat cycle interleave interpose
Seq with head-items missing: rest next fnext nnext drop drop-while nthnext for
Seq with tail-items missing: take take-nth take-while butlast drop-last for
Rearrangment of a seq: flatten reverse sort sort-by shuffle
Create nested seqs: split-at splitv-at split-with partition partition-all partition-by partitionv partitionv-all
Process each item of a seq to create a new seq: map pmap mapcat for replace reductions map-indexed seque

Using a seq

Extract a specific-numbered item from a seq: first ffirst nfirst second nth when-first last rand-nth
Construct a collection from a seq: zipmap into reduce set vec into-array to-array-2d frequencies group-by
Pass items of a seq as arguments to a function: apply
Compute a boolean from a seq: not-empty some reduce seq? every? not-every? not-any? empty?
Search a seq using a predicate: some filter
Force evaluation of lazy seqs: doseq dorun doall
Check if lazy seqs have been forcibly evaluated: realized?

Creating a seq

Lazy seq from collection: seq vals keys rseq subseq rsubseq
Lazy seq from producer function: lazy-seq repeatedly iterate
Lazy seq from constant: repeat range
Lazy seq from other objects: line-seq resultset-seq re-seq tree-seq file-seq xml-seq iterator-seq enumeration-seq