与列表(它是一个顺序数据结构)和向量(它既是顺序数据又是关联数据)不同,映射完全是一个关联数据结构。映射由键到值的一组映射组成。所有键都是唯一的,因此映射支持从键到值的“恒定”时间查找。
一张映射用花括号表示:
{} ;;=> {} {: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任何非映射条目的电话,都会收到ClassCastException:
(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"})