跳轉到內容

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}
華夏公益教科書