Clojureのコレクション(collection)は値を複合的な値に「集める」(collect)。Clojureのコレクション型には重要なものが4種類ある: ベクター、リスト、セット、マップだ。4種類のコレクション型のうち、ベクターとリストは順序付き(ordered)だ。

ベクター

ベクターはインデックス付き(indexed)でシーケンシャル(sequential)なデータ型だ。ベクターはこのように [ ] で表される:

[1 2 3]

インデックスアクセス

「インデックス付き」(indexed)とは、ベクターの要素がインデックスで取得できることを意味する。Clojureでは(Javaと同様に)インデックスは1ではなく0から始まる。要素をインデックスで取得するには get を使う:

user=> (get ["abc" false 99] 0)
"abc"
user=> (get ["abc" false 99] 1)
false

無効なインデックスでgetを呼び出すと nil が返ってくる:

user=> (get ["abc" false 99] 14)
nil

count

すべてのClojureコレクションは数えられる(counted):

user=> (count [1 2 3])
3

構築する

リテラルの [ ] というシンタックスに加えて、Clojureのベクターは vector 関数で作ることもできる:

user=> (vector 1 2 3)
[1 2 3]

要素を追加する

要素は conj (conjoinの略)を使うことでベクターに追加される。要素は常にベクターの最後に追加される:

user=> (conj [1 2 3] 4 5 6)
[1 2 3 4 5 6]

イミュータビリティ(不変性)

Clojureコレクションは、イミュータビリティや値による等価性比較といった、文字列や数値などの単純な値と共通して重要な性質を備えている。

例えば、ベクターを作って conj で変更してみよう。

user=> (def v [1 2 3])
#'user/v
user=> (conj v 4 5 6)
[1 2 3 4 5 6]

ここで conj は新しいベクターを返すが、もとのベクターを調べてみると変化していないことが分かる:

user=> v
[1 2 3]

コレクションを「変更」するあらゆる関数は新しいインスタンスを返す。これを上手く利用するにはプログラムが変更されたインスタンスを覚えておいたり持ち回ったりする必要があるだろう。

リスト

リストはシーケンシャル(sequential)な連結リストであり、ベクターのように末尾ではなくリストの先頭に新しい要素を追加する。

構築する

リストは最初の要素を関数として呼び出すことで評価されるので、評価を避けるためにはリストをクォート(quote)しなければならない:

(def cards '(10 :ace :jack 9))

リストはインデックス付き(indexed)ではないので firstrest でたどらなければならない。

user=> (first cards)
10
user=> (rest cards)
'(:ace :jack 9)

要素を追加する

conj はベクターと同様にリストに要素を追加するのに利用することができる。しかし、 conj は常にそのデータ構造で定数時間で要素追加可能な場所に要素を追加する。リストの場合には要素は前に追加される:

user=> (conj cards :queen)
(:queen 10 :ace :jack 9)

スタックアクセス

リストはpeekとpopでスタックとして使うこともできる:

user=> (def stack '(:a :b))
#'user/stack
user=> (peek stack)
:a
user=> (pop stack)
(:b)