## 集合
Clojure提供這些集合類型: list, vector, set, map。同時Clojure還可以使用Java里面提供的將所有的集合類型,但是通常不會這樣做的, 因為Clojure自帶的集合類型更適合函數式編程。
Clojure集合有著java集合所不具備的一些特性。所有的clojure集合是不可修改的、異源的以及持久的。不可修改的意味著一旦一個集合產生之后,你不能從集合里面刪除一個元素,也往集合里面添加一個元素。異源的意味著一個集合里面可以裝進任何東西(而不必須要這些東西的類型一樣)。持久的以為著當一個集合新的版本產生之后,舊的版本還是在的。CLojure以一種非常高效的,共享內存的方式來實現這個的。比如有一個map里面有一千個name-valuea pair, 現在要往map里面加一個,那么對于那些沒有變化的元素, 新的map會共享舊的map的內存,而只需要添加一個新的元素所占用的內存。
有很多核心的函數可以用來操作所有這些類型的集合。。多得以至于無法在這里全部描述。其中的一小部分我們會在下面介紹vector的時候介紹一下。要記住的是,因為clojure里面的集合是不可修改的,所以也就沒有對集合進行修改的函數。相反clojure里面提供了一些函數來從一個已有的集合來高效地創建新的集合 — 使用 [persistent data structures](http://en.wikipedia.org/wiki/Persistent_data_structure) 。同時也有一些函數操作一個已有的集合(比如vector)來產生另外一種類型的集合(比如LazySeq), 這些函數有不同的特性。
提醒: 這一節里面介紹的Clojure集合對于學習clojure來說是非常的重要。但是這里介紹一個函數接著一個函數,所以你如果覺得有點煩,有點乏味,你可以跳過,等用到的時候再回過頭來查詢。
`count` 返回集合里面的元素個數,比如:
```
(count [19 "yellow" true]) ; -> 3
```
`conj` 函數是 conjoin的縮寫, 添加一個元素到集合里面去,到底添加到什么位置那就取決于具體的集合了,我們會在下面介紹具體集合的時候再講。
`reverse` 把集合里面的元素反轉。
```
(reverse [2 4 7]) ; -> (7 4 2)
```
`map` 對一個給定的集合里面的每一個元素調用一個指定的方法,然后這些方法的所有返回值構成一個新的集合(LazySeq)返回。這個指定了函數也可以有多個參數,那么你就需要給map多個集合了。如果這些給的集合的個數不一樣,那么執行這個函數的次數取決于個數最少的集合的長度。比如:
```
; The next line uses an anonymous function that adds 3 to its argument.
(map #(+ % 3) [2 4 7]) ; -> (5 7 10)
(map + [2 4 7] [5 6] [1 2 3 4]) ; adds corresponding items -> (8 12)
```
`apply` 把給定的集合里面的所有元素一次性地給指定的函數作為參數調用,然后返回這個函數的返回值。所以apply與map的區別就是map返回的還是一個集合,而apply返回的是一個元素, 可以把apply看作是SQL里面的聚合函數。比如:
```
(apply + [2 4 7]); -> 13
```
有很多函數從一個集合里面獲取一個元素,比如:
```
(def stooges ["Moe" "Larry" "Curly" "Shemp"])
(first stooges) ; -> "Moe"
(second stooges) ; -> "Larry"
(last stooges) ; -> "Shemp"
(nth stooges 2) ; indexes start at 0 -> "Curly"
```
也有一些函數從一個集合里面獲取多個元素,比如:
```
(next stooges) ; -> ("Larry" "Curly" "Shemp")
(butlast stooges) ; -> ("Moe" "Larry" "Curly")
(drop-last 2 stooges) ; -> ("Moe" "Larry")
; Get names containing more than three characters.
(filter #(> (count %) 3) stooges) ; -> ("Larry" "Curly" "Shemp")
(nthnext stooges 2) ; -> ("Curly" "Shemp")
```
有一些謂詞函數測試集合里面每一個元素然后返回一個布爾值,這些函數都是”short-circuit”的,一旦它們的返回值能確定它們就不再繼續測試剩下的元素了,有點像java的&&和or, 比如:
```
(every? #(instance? String %) stooges) ; -> true
(not-every? #(instance? String %) stooges) ; -> false
(some #(instance? Number %) stooges) ; -> nil
(not-any? #(instance? Number %) stooges) ; -> true
```