2012-03-11 30 views
1

我有一組對象如何在更新特定鍵的元素後獲得修改後的Set?

(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中做這件事的慣用方式是什麼?

+0

你是什麼意思「給定密鑰」?從你的例子你有一套包含三個地圖。在你想要的用法例子中,你傳遞了這個集合和一個新的地圖......但這不是一個真正的關鍵。你想用':isbn'爲1來更新地圖嗎? – djhworld 2012-03-11 17:04:11

+0

編輯更新:isbn – Sathish 2012-03-11 17:09:25

+0

我想知道是否可以改進數據結構以反映:isbn應該是唯一的。 – 2012-03-11 17:18:43

回答

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

如果你想要做這種更新的,你應該有一個關聯結構。但是你可以打開設置成一個,然後再返回:

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

此代碼假定:ISBN是唯一的(因爲你說的「鑰匙」)。它將該集合變成一個映射,從:isbn值到相應記錄的序列,用作者更新第一條記錄:isbn 1,然後將其重新集合到一個集合中。

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))) 
相關問題