如何在更新特定键的元素后获得修改后的Set?

时间:2012-03-11 16:48:31

标签: clojure

我有一组对象

(def books #{{:isbn 1 :title "Programming Clojure"}
             {:isbn 2 :title "Joy of Clojure"}
             {:isbn 3 :title "Clojure in Action"}})

如何更新具有给定键(:isbn)的对象并返回修改后的集?

(??? books :isbn {:isbn 1 :title "Programming Clojure" :author "Halloway"})

在Java中,可以使用isbn定义相等性,并且可以将元素直接添加到Set中。在Clojure中这样做的惯用方法是什么?

3 个答案:

答案 0 :(得分:2)

如果要进行此类更新,则应具有关联结构。但是你可以将这个集合变为一个然后再变回:

(-> (group-by :isbn books)
    (assoc-in [1 0 :author] "Halloway") ; 1 is the isbn, 0 means "first"
    vals 
    (->> (map first)) 
    set)

此代码假定:isbn是唯一的(因为你说“key”)。它将集合转换为映射:isbn值到相应记录的序列,用作者:isbn 1更新第一条记录,然后将其重新组合成一组。

答案 1 :(得分:0)

假设您使用的是ISBN编号作为“密钥”,这是我的解决方案

(defn update-set [coll k new-map]
   (reduce (fn [new-set existing-map] 
             (if (= (k existing-map) (k new-map)) 
               (conj new-set new-map) 
               (conj new-set existing-map))) #{} coll)) 

(update-set books :isbn {:isbn 1 :title "Programming Clojure" :author "Halloway"})
; => #{{:title "Joy of Clojure", :isbn 2} {:author "Halloway", :title "Programming Clojure",   :isbn 1} {:title  "Clojure in Action", :isbn 3}}

答案 2 :(得分:0)

以下Clojure函数,update-if-isbn是非公共函数,将解决您的问题。

(defn- update-if-isbn [isbn k v book] 
  (if (= (:isbn book) isbn) (assoc book k v) book))

(defn update-books [isbn k v books] 
  (set (map (partial update-if-isbn isbn k v) books)))