跳转到内容

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"}}

update-in

[编辑 | 编辑源代码]
 (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

defstruct

[编辑 | 编辑源代码]

更多信息请参见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}
华夏公益教科书