Clojure 编程/示例/API 示例/高级数据结构
外观
(get {:a 1, :b 2} :a)
;; ⇒ 1
get还可以接受可选的第三个参数,如果映射中没有找到键,则返回该参数
(get {:a 1, :b 2} :e 0)
;; ⇒ 0
;;maps are functions of their keys (and keys likewise), they delegate to get:
({:a 1, :b 2, :c 3} :a)
;; ⇒ 1
(:b {:a 1, :b 2} 99)
;; ⇒ 2
(def nested-structure { :level 0,
:nested1 { :level 1,
:nested2 { :level 2,
:final-data "initial data"}}})
(assoc-in nested-structure [:nested1 :nested2 :final-data] "new data")
;; ⇒ {:level 0, :nested1 {:nested2 {:level 2, :final-data "new data"}, :level 1}}
将两个映射合并成一个更大的映射
(merge {:a 1} {:b 2})
;; ⇒ {:a 1, :b 2})
(merge-with + {:a 1} {:a 2, :b 3})
;; ⇒ {:a 3 :b 3}
使用merge-with(ClojureDocs),您可以指定针对冲突采取什么行动,这里我们决定将冲突加入到一个使用union的集合 (菜谱中的集合)
;; We have two maps with sets of normal users and malicious users
;; and we'll try merging them
(use 'clojure.set)
(def group1 {:normal #{"Alice" "Bob"} :malicious #{"Eve"}})
(def group2 {:normal #{"Spock" "Alice"} :malicious #{"Sauron"}})
;; Naïve attempt
(merge group1 group2)
;; ⇒ {:malicious #{"Sauron"}, :normal #{"Alice" "Spock"}}
;; Wait, where did "Eve" go? Where did "Bob" go? We'll have to use merge-with:
(merge-with union group1 group2)
;; ⇒ {:malicious #{"Sauron" "Eve"}, :normal #{"Alice" "Bob" "Spock"}}
(def my-map {:a 1 :b 2})
(update-in my-map [:a] #(- % 4))
;; ⇒ {:a -3, :b 2}
(defstruct employee :name :id)
(def e (struct employee "John" 123))
e
;; ⇒ {:name "John", :id 123}
("name" e) ; FAIL: string not an accessor
;; ERROR ⇒ java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IFn (NO_SOURCE_FILE:0)
(:name e)
;; ⇒ "John"
(def employee-name (accessor employee :name)) ; bind accessor to e-name
(employee-name e) ; use accessor
;; ⇒ "John"
更多信息请参见struct-map。
更多信息请参见struct-map。
更多信息请参见struct-map。
(defstruct employee :name :id)
(struct employee "Mr. X" 10)
;; ⇒ {:name "Mr. X", :id 10}
(struct-map employee :id 20 :name "Mr. Y")
;; ⇒ {:name "Mr. Y", :id 20}
(def a (struct-map employee :id 20 :name "Mr. Y"))
(def b (struct employee "Mr. X" 10))
;; observe that :name and :id are accessors
(:name a) ; ⇒ "Mr. Y"
(:id b) ; ⇒ 10
(b :id) ; ⇒ 10
(b :name) ; ⇒ "Mr. X"
(assoc a :name "New Name")
;; ⇒ {:name "New Name", :id 20}
a ; note that 'a' is immutable and did not change
;; ⇒ {:name "Mr. Y", :id 20}
(def a1 (assoc a :name "Another New Name")) ; bind to a1
a1
;; ⇒ {:name "Another New Name", :id 20}
#{1 2 2 3 \a 4 \a "test" "test1" "test"}
;; ⇒ #{1 \a 2 3 4 "test" "test1"}
(clojure.set/union #{1 2 3} #{1 4 7})
;; ⇒ #{1 2 3 4 7}
(clojure.set/index [{:a 1 :b 2} {:a 1 :b 4}] [:a :b])
;; ⇒ {{:b 4, :a 1} #{{:a 1, :b 4}}, {:b 2, :a 1} #{{:a 1, :b 2}}}
(clojure.set/index [{:a 1 :b 2} {:a 1 :b 4}] [:a])
;; ⇒ {{:a 1} #{{:a 1, :b 4} {:a 1, :b 2}}}
(clojure.set/select odd? #{1 2 3 4})
;; ⇒ #{1 3}
(clojure.set/project [{:a 1 :b 2 :c 3} {:a 4 :b 5 :c 6}] [:a :b])
;; ⇒ #{{:b 2, :a 1} {:b 5, :a 4}}
(clojure.set/join #{{:a 1 :b 2} {:a 3 :b 4}} #{{:c 5 :d 6} {:c 1 :d 8}} {:a :c})
;; ⇒ #{{:d 8, :c 1, :a 1, :b 2}}
(-> (zip/vector-zip [[1 2] 3 [[4 5] 7 8]])
zip/down
zip/right
zip/right
zip/down
zip/down
zip/right
(zip/edit inc)
zip/root)
;; ⇒ [[1 2] 3 [[4 6] 7 8]]
拉链是一种以函数式方式修改树的方式 - 要方便地做到这一点,您需要一种方法来“深入”树的某个分支并执行本地编辑,而无需费力地重新构建树的较高区域。在这个例子中,vector-zip 函数将嵌套数组转换为拉链。然后,我们使用“down”和“right”来“深入”拉链。到达我们要编辑的节点后,我们使用“edit”进行编辑,在本例中,增加数字。然后我们可以调用“root”将拉链转换回嵌套数组。请注意,我们能够以非常优雅的方式有效地对树进行精确的更改。
(zipmap '(\a \b \c) '(1 2 3))
;; ⇒ {\c 3, \b 2, \a 1}
(let [ks [1 3 4]] (zipmap ks (map inc ks)))
;; ⇒ {4 5, 3 4, 1 2}