Clojure學習03:數據結構(集合)

Clojure提供了幾種強大的數據結構(集合)java

1、集合種類python

一、vector編程

至關於數組,如: [2  3   5]  ,  ["ad"  "adas"  "adadsads"]數組

二、list數據結構

至關於鏈表,如: '(2  3   5)  ,  '("ad"  "adas"  "adadsads")app

與vector相比,[]變成了() ,又由於 ()符號是用於函數調用,爲了區別,須要在 ( 前面加上  一個單引號'編程語言

三、map函數式編程

語法格式如: {:a  1  :b  1} 函數

map是1個或多個 key-value對,其中key標識符前面要求有:標識 。map的key自己就是函數,經過它能夠查找它所對應的值。url

如:

user=> (def data {:a 1 :b 2} )

user=> (:a data)
1
user=> (:a {:a 1 :b 2} )
1
user=> (:a {:a 3 :b 2} )
3

上面第一個語句定義了一個值data,是個map。 第二個語句是獲取關鍵字:a的值,這裏:a就是一個函數。
最後兩個語句就是直接從map字面量上查詢key對應的值。

四、set

語法格式如: #{值1  值2  ....}

user=> #{1 2 3}
#{1 3 2}

說明,相比java的集合,Clojure的集合對象有以下幾個特徵:

1) immutable  集合的內容在初始化後是不可修改的,後續對它的操做都會產生新的集合

2)heterogeneous  多相(異種的),集合中的元素不要求必須是同一種數據類型,能夠是不一樣類型數據的集合

3)persistent 持久化的,集合的內容是不可修改的,相關的操做會產生新的集合,但並非複製的方式,而是有點相似配置管理的機制,只是新增變動的部分,老的部分仍是採用原來的數據。這樣全部的歷史數據都能完整的保留下來。

 

2、集合的三大操做

全部函數式編程語言,都對集合的操做提供了一些基礎的高階函數,最典型的是  filter ,map 和 reduce三個函數。

這個三個函數高度歸納了對集合的操做。

下面咱們分別介紹。

 

一、filter函數

filter函數是函數式編程中對集合操做的三大重要操做之一,幾乎全部的支持函數式編程的語言都有相似的方法。

其做用是篩選出知足條件的元素組成一個新的集合返回。

filter函數須要兩個參數,第一個是過濾函數,用於檢查元素是否符合,第二個是集合自己。結果返回一個list。

以下面例子:

例1:

user=> (def stooges ["Moe" "Larry" "Curly" "Shemp"])
#'user/stooges
user=> (filter #(> (count %) 3) stooges)
("Larry" "Curly" "Shemp")

上面代碼中的count函數是計算字符串的長度, #(> (count %) 3) 是個匿名函數,只有長度大於3的字符串才知足條件。

例2:

user=> (def years [1940 1944 1961 1985 1987])
#'user/years
user=> (filter #(even? %) years)
(1940 1944)

 

二、map

map函數是函數式編程中對集合操做的三大重要操做之一,幾乎全部的支持函數式編程的語言都有相似的方法。

其做用是 對集合中的每個元素作處理,最後獲得一個新的集合(注意集合類型是列表),新集合的元素個數和原集合同樣,但內容能夠不同(包括元素的類型)。

因此map函數 的第一個參數是對元素轉換的處理函數,後面的參數是待處理的集合(一個或多個)。

下面咱們舉例來講明:

例1:

(defn fun [item] (* item 2))   //定義了一個函數,返回的值是對輸入參數乘以2

(map fun [1 2 3])   //map函數使用了fun函數,最後map函數調用後的返回結果爲 (2 4 6)

能夠看出,被處理的集合是vector,但處理後返回的集合類型爲list

例2:

user=> (map fun #{1 2 3}) (2 6 4)

能夠看出,set被處理後返回的集合類型也是列表,並且由於set自己是無序的,返回的list結果序號與set表面上看的也不一致。

例3:

user=> (map + [2 4] [5 6] [1 2]) (8 12)

user=> (map + [2 4 7] [5 6] [1 2 3 4]) (8 12)

上面兩個例子傳入的第一個參數是函數是 + , 後面是多個集合。最後的結果是按照最小的集合元素算的。

例4:

user=> (map #(* % 2) [1 2 3]) (2 4 6)

上面代碼中傳給map的是一個匿名函數  #(* % 2) 。在實際的集合map操做中,大量場景下會傳入匿名函數。

Clojure中的匿名函數就相似於 python、java8中的lambda表達式。

 

三、reduce

reduce函數是函數式編程中對集合操做的三大重要操做之一,幾乎全部的支持函數式編程的語言都有相似的方法。

其做用是對集合作處理,獲得一個計算後的值。 如sum ,count, max, min 都是reduce操做的特例,只不過這些操做是很是常見和通用的 ,會被提爲專門的方法。

如:

user=> (reduce #(+ %1 %2) [1 2 3])
6

上面操做是對集合求和。reduce的第一個參數是一個函數,這裏是匿名函數,該匿名第一個參數(用1%代替)是每次迭代的返回值,%2是元素。

每次對元素操做,1%都會從新最後做爲參數傳入,最後一個元素處理完後%1的值會做爲reduce的函數值返回。

user=> (reduce #(* %1 %2) [2 4 6])
48

上面操做是對集合中的元素求乘積。

user=> (reduce #(if (> %1 %2) %1 %2) [10 2 54 3 6])
54
user=> (reduce #(if (< %1 %2) %1 %2) [10 2 54 3 6])
2

上面的兩個操做分別是取最大值和最小值。

 

3、集合的其它操做

下面介紹的集合的操做都是對上述三大操做的一些特例。

一、count函數

該函數用於獲取集合中的元素個數

user=> (count [19 "yellow" true])
3
user=> (count '(19 "yellow" true))
3
user=> (count #{19 "yellow" true})
3
user=> (count {:a 1 :b 2})
2

從上面例子能夠看出,count函數對這四種集合都是適合的。

 

二、reverse

該函數是對集合中的數據進行反轉排列,返回一個新的集合。由於map和set自己是無序的數據結構,因此reverse函數也只對vector和list有意義。

user=> (reverse [2 4 7])
(7 4 2)
user=> (reverse '(2 4 7))
(7 4 2)

 

三、map

map函數的做用是 對集合中的每個元素作處理,最後獲得一個新的集合(注意集合類型是列表),新集合的元素個數和原集合同樣,但內容能夠不同(包括元素的類型)。

因此map函數 的第一個參數是對元素轉換的處理函數,後面的參數是待處理的集合(一個或多個)。

下面咱們舉例來講明:

例1:

(defn fun [item] (* item 2))   //定義了一個函數,返回的值是對輸入參數乘以2

(map fun [1 2 3])   //map函數使用了fun函數,最後map函數調用後的返回結果爲 (2 4 6)

能夠看出,被處理的集合是vector,但處理後返回的集合類型爲list

例2:

user=> (map fun #{1 2 3})
(2 6 4)

能夠看出,set被處理後返回的集合類型也是列表,並且由於set自己是無序的,返回的list結果序號與set表面上看的也不一致。

例3:

user=> (map + [2 4] [5 6] [1 2])
(8 12)

user=> (map + [2 4 7] [5 6] [1 2 3 4])
(8 12)

上面兩個例子傳入的第一個參數是函數是 + , 後面是多個集合。最後的結果是按照最小的集合元素算的。

例4:

user=> (map #(* % 2) [1 2 3])
(2 4 6)

上面代碼中傳給map的是一個匿名函數  #(* % 2) 。在實際的集合map操做中,大量場景下會傳入匿名函數

Clojure中的匿名函數就相似於 python、java8中的lambda表達式。

 

四、apply

該函數的做用是給它傳入一個函數和集合,該函數對整個集合進行操做後返回的結果就是apply函數的返回結果。

 user=> (apply + [2 4 6])
12
user=> (apply * [2 4 6])
48
user=> (apply - [2 4 6])
-8

 

五、從集合中獲取單個元素

user=> (def stooges ["Moe" "Larry" "Curly" "Shemp"])
#'user/stooges
user=> (first stooges)
"Moe"
user=> (second stooges)
"Larry"
user=> (last stooges)
"Shemp"
user=> (nth stooges 2)
"Curly"

最後一個方法nth的第2個參數表示獲取第幾個元素(從0開始,這裏2表明第3個元素)。

 

六、從集合中獲取多個元素

user=> (def stooges ["Moe" "Larry" "Curly" "Shemp"])
#'user/stooges


user=> (next stooges)
("Larry" "Curly" "Shemp")

user=> (nthnext stooges 1)
("Larry" "Curly" "Shemp")

user=> (nthnext stooges 2)
("Curly" "Shemp")
user=> (butlast stooges)
("Moe" "Larry" "Curly")

user=> (drop-last 1 stooges)
("Moe" "Larry" "Curly")
user=> (drop-last 2 stooges)
("Moe" "Larry")

七、some

該函數能夠用來判斷集合中是否包含某個元素,須要一個用來判斷的函數做爲參數,另外一個參數是集合自己。如:

user=>  (def stooges ["Moe" "Larry" "Curly" "Shemp"])
#'user/stooges
user=> (some #(= % "Moe") stooges)
true
user=> (some #(= % "Mark") stooges)
nil

能夠看出,若是存在則返回true,不然返回nil(爲什麼不返回false呢?)。

上面的寫法會看起來比較笨拙,能夠用以下的方法達到一樣目的:

user=> (contains? (set stooges) "Moe")
true
user=> (contains? (set stooges) "Mark")
false

上面操做,利用set方法將vector轉換爲set集合,而後利用contains?函數進行判斷,看上去會更清晰簡單些。

另一個區別是,當元素不存在時返回的不是nil,而是false

相關文章
相關標籤/搜索