Learn Clojure - Sequential Collections シーケンシャルなコレクション
Clojure collections "collect" values into compound values. Clojureのコレクションとは、任意個の値を集めて(コレクトして)、1つの複合的な値としたものだ。There are four key Clojure collection types: vectors, lists, sets, and maps. Clojureにおいて重要なコレクション型は、ベクタ、リスト、セット、マップの4つである。Of those four collection types, vectors, and lists are ordered. これら4つのコレクション型のうち、ベクタとリストは順序のあるコレクションである。
Vectors ベクタ
Vectors are an indexed, sequential data structure. ベクタは整数の添字を持つ、シーケンシャルなデータ構造だ。Vectors are represented with [ ]
like this: ベクタは次のように[ ]
を使って表される。
[1 2 3]
Indexed access 添字によるアクセス
"Indexed" means that elements of a vector can be retrieved by index. 「添字を持つ」とは、添字を指定することでベクタの要素が取り出せるということである。In Clojure (as in Java), indexes start at 0, not 1. (Java同様)Clojureでは、添字は(1ではなく)0から始まる。Use the get
function to retrieve an element at an index: ある添字に対応する要素を取り出すには、次のようにget
関数を使う。
user=> (get ["abc" false 99] 0) "abc" user=> (get ["abc" false 99] 1) false
Calling get with an invalid index returns nil
: 無効な添字とともにgetを呼べばnilが返される。
user=> (get ["abc" false 99] 14) nil
count
All Clojure collections can be counted: count
関数によってClojureの任意のコレクションの要素数を得られる。
user=> (count [1 2 3]) 3
Constructing 生成
In addition to the literal [ ]
syntax, Clojure vectors can be created with the vector
function: [ ]
というリテラルな構文で生成する以外にも、vector
関数によってもベクタを生成することができる。
user=> (vector 1 2 3) [1 2 3]
Adding elements 要素の追加
Elements are added to a vector with conj
(short for conjoin). conjoin(繋げる)という意味のconj
関数を使えば要素をベクタに追加できる。Elements are always added to a vector at the end: ベクタにおいては要素は常に右側に追加される。
user=> (conj [1 2 3] 4 5 6) [1 2 3 4 5 6]
Immutability 不変性
Clojure collections share important properties of simple values like strings and numbers, such as immutability and equality comparison by value. 文字列や数といったシンプルな値と同じ重要な属性を、Clojureのどのコレクションも共有している。つまり不変であり、値として等しさを比較できる。
For example, lets create a vector and modify it with conj
. 例えば、次のようにベクタを作りconj
で変更してみよう。
user=> (def v [1 2 3]) #'user/v user=> (conj v 4 5 6) [1 2 3 4 5 6]
Here conj
returned a new vector but if we examine the original vector, we see it's unchanged: 行ったconj
は新しいベクタを返した。しかし元のベクタを見てみると、元のベクタは変更されていないことが確認できる。
user=> v [1 2 3]
Any function that "changes" a collection returns a new instance. コレクションを「変更する」どの関数も、新しいインスタンスを返す。Your program will need to remember or pass along the changed instance to take advantage of it. 変更を有効にするためには、変更後のインスタンスを保持したり、別の関数に渡して利用したりする必要がある。
Lists リスト
Lists are sequential linked lists that add new elements at the head of the list, instead of at the tail like vectors. リストはシーケンシャルな連結リストであり、ベクタにおいては新要素が右側に追加されたのとは異なり、リストでは左側に追加される。
Constructing 生成
Because lists are evaluated by invoking the first element as a function, we must quote a list to prevent evaluation: リストは第1要素を関数とする呼び出しとして評価されるため、評価をさせないためには'
を使ってリストをクォートする必要がある。
(def cards '(10 :ace :jack 9))
Lists are not indexed so they must be walked using first
and rest
. リストには添字がない。そのため、first
やrest
を使って要素を辿らねばならない。
user=> (first cards) 10 user=> (rest cards) '(:ace :jack 9)
Adding elements 要素の追加
conj
can be used to add elements to a list just as with vectors. ベクタと同様リストについてもconj
によって要素を追加できる。However, conj
always adds elements where it can be done in constant time for the data structure. しかし、conj
は常に、対象となるデータ構造において定数時間で実現できる方法で要素を追加しようとする。In the case of lists, elements are added at the front: リストの場合は要素は左側に追加される。
user=> (conj cards :queen) (:queen 10 :ace :jack 9)
Stack access スタックとしてのアクセス
Lists can also be used as a stack with peek and pop: 関数peek
(覗く)およびpop
(外す)を使うことで、リストを(後入れ先出しの)スタック構造として使うことができる。
user=> (def stack '(:a :b)) #'user/stack user=> (peek stack) :a user=> (pop stack) (:b)