地圖
與列表(順序資料結構)和向量(順序和關聯)不同,對映僅是關聯資料結構。對映由一組從鍵到值的對映組成。所有鍵都是唯一的,因此 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
你可以分別使用 key
或 val
從地圖條目中提取關鍵字或值 :
(key (find {:foo :bar} :foo))
;;=> :foo
(val (find {:foo :bar} :foo))
;;=> :bar
請注意,儘管所有 Clojure 對映條目都是向量,但並非所有向量都是對映條目。如果你嘗試在任何不是地圖條目的地方呼叫 key
或 val
,你將獲得一個知識 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
獲得的序列中的專案的順序是未定義的。
你可以分別使用 keys
或 vals
獲取一系列關鍵字或地圖中的值 :
(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"})