地圖

與列表(順序資料結構)和向量(順序和關聯)不同,對映僅是關聯資料結構。對映由一組從鍵到值的對映組成。所有鍵都是唯一的,因此 map 支援從鍵到值的常量時間查詢。

地圖用花括號表示:

{}
;;=> {}

{:foo :bar}
;;=> {:foo :bar}

{:foo :bar :baz :qux}
;;=> {:foo :bar, :baz :qux}

每對兩個元素是鍵值對。因此,例如,上面的第一張地圖沒有對映。第二個有一個對映,從關鍵:foo 到值:bar。第三個有兩個對映,一個從關鍵:foo 到值:bar,一個從關鍵:baz 到值:qux。對映本質上是無序的,因此對映的顯示順序無關緊要:

(= {:foo :bar :baz :qux}
   {:baz :qux :foo :bar})
;;=> true

你可以使用 map? 謂詞測試某些內容是否為地圖 :

(map? {})
;;=> true

(map? {:foo :bar})
;;=> true

(map? {:foo :bar :baz :qux})
;;=> true

(map? nil)
;;=> false

(map? 42)
;;=> false

(map? :foo)
;;=> false

你可以使用 contains? 謂詞測試地圖是否在常量時間內包含給定

(contains? {:foo :bar :baz :qux} 42)
;;=> false

(contains? {:foo :bar :baz :qux} :foo)
;;=> true

(contains? {:foo :bar :baz :qux} :bar)
;;=> false

(contains? {:foo :bar :baz :qux} :baz)
;;=> true

(contains? {:foo :bar :baz :qux} :qux)
;;=> false

(contains? {:foo nil} :foo)
;;=> true

(contains? {:foo nil} :bar)
;;=> false

你可以使用 get 獲取與金鑰關聯的值 :

(get {:foo :bar :baz :qux} 42)
;;=> nil

(get {:foo :bar :baz :qux} :foo)
;;=> :bar

(get {:foo :bar :baz :qux} :bar)
;;=> nil

(get {:foo :bar :baz :qux} :baz)
;;=> :qux

(get {:foo :bar :baz :qux} :qux)
;;=> nil

(get {:foo nil} :foo)
;;=> nil

(get {:foo nil} :bar)
;;=> nil

此外,對映本身是獲取鍵並返回與該鍵關聯的值的函式:

({:foo :bar :baz :qux} 42)
;;=> nil

({:foo :bar :baz :qux} :foo)
;;=> :bar

({:foo :bar :baz :qux} :bar)
;;=> nil

({:foo :bar :baz :qux} :baz)
;;=> :qux

({:foo :bar :baz :qux} :qux)
;;=> nil

({:foo nil} :foo)
;;=> nil

({:foo nil} :bar)
;;=> nil

你可以使用 find 將整個地圖條目(鍵和值一起)作為雙元素向量獲取

(find {:foo :bar :baz :qux} 42)
;;=> nil

(find {:foo :bar :baz :qux} :foo)
;;=> [:foo :bar]

(find {:foo :bar :baz :qux} :bar)
;;=> nil

(find {:foo :bar :baz :qux} :baz)
;;=> [:baz :qux]

(find {:foo :bar :baz :qux} :qux)
;;=> nil

(find {:foo nil} :foo)
;;=> [:foo nil]

(find {:foo nil} :bar)
;;=> nil

你可以分別使用 keyval 從地圖條目中提取關鍵字或值 :

(key (find {:foo :bar} :foo))
;;=> :foo

(val (find {:foo :bar} :foo))
;;=> :bar

請注意,儘管所有 Clojure 對映條目都是向量,但並非所有向量都是對映條目。如果你嘗試在任何不是地圖條目的地方呼叫 keyval,你將獲得一個知識 15

(key [:foo :bar])
;; java.lang.ClassCastException:

(val [:foo :bar])
;; java.lang.ClassCastException:

你可以使用 map-entry? 謂詞測試某些內容是否為地圖條目 :

(map-entry? (find {:foo :bar} :foo))
;;=> true

(map-entry? [:foo :bar])
;;=> false

你可以使用 assoc 獲取具有與現有地圖相同的鍵值對的地圖,並新增或更改一個對映:

(assoc {} :foo :bar)
;;=> {:foo :bar}

(assoc (assoc {} :foo :bar) :baz :qux)
;;=> {:foo :bar, :baz :qux}

(assoc {:baz :qux} :foo :bar)
;;=> {:baz :qux, :foo :bar}

(assoc {:foo :bar :baz :qux} :foo 42)
;;=> {:foo 42, :baz :qux}

(assoc {:foo :bar :baz :qux} :baz 42)
;;=> {:foo :bar, :baz 42}

你可以使用 dissoc 獲取具有與現有地圖相同的鍵值對的地圖,可能刪除了一個地圖:

(dissoc {:foo :bar :baz :qux} 42)
;;=> {:foo :bar :baz :qux}

(dissoc {:foo :bar :baz :qux} :foo)
;;=> {:baz :qux}

(dissoc {:foo :bar :baz :qux} :bar)
;;=> {:foo :bar :baz :qux}

(dissoc {:foo :bar :baz :qux} :baz)
;;=> {:foo :bar}

(dissoc {:foo :bar :baz :qux} :qux)
;;=> {:foo :bar :baz :qux}

(dissoc {:foo nil} :foo)
;;=> {}

count 以恆定時間返回對映數:

(count {})
;;=> 0

(count (assoc {} :foo :bar))
;;=> 1

(count {:foo :bar :baz :qux})
;;=> 2

你可以使用 seq 獲取地圖中所有條目的序列:

(seq {})
;;=> nil

(seq {:foo :bar})
;;=> ([:foo :bar])

(seq {:foo :bar :baz :qux})
;;=> ([:foo :bar] [:baz :qux])

同樣,地圖是無序的,因此通過在地圖上呼叫 seq 獲得的序列中的專案的順序是未定義的。

你可以分別使用 keysvals 獲取一系列關鍵字或地圖中的值 :

(keys {})
;;=> nil

(keys {:foo :bar})
;;=> (:foo)

(keys {:foo :bar :baz :qux})
;;=> (:foo :baz)

(vals {})
;;=> nil

(vals {:foo :bar})
;;=> (:bar)

(vals {:foo :bar :baz :qux})
;;=> (:bar :qux)

Clojure 1.9 新增了一個文字語法,用於更簡潔地表示金鑰共享相同名稱空間的對映。請注意,兩種情況下的對映都是相同的(對映不知道預設名稱空間),這僅僅是語法上的便利。

;; typical map syntax
(def p {:person/first"Darth" :person/last "Vader" :person/email "darth@death.star"})

;; namespace map literal syntax
(def p #:person{:first "Darth" :last "Vader" :email "darth@death.star"})