2013-04-13 44 views
6

我在Clojure中圍繞着我的狀態。我來自可以突變狀態的語言。例如,在Python中,我可以創建一個字典,在其中放入一些字符串=>整數對,然後遍歷字典並遞增值。如何在地圖中增加值

我該如何在習慣Clojure中做到這一點?

回答

1

只是produce新地圖,並使用它:

(def m {:a 3 :b 4}) 

(apply merge 
    (map (fn [[k v]] {k (inc v) }) m)) 

; {:b 5, :a 4} 
+0

一個價值怎麼樣?那麼,如果我想要{a:7:b 4}。如果我有一個整數地圖的地圖,並想增加說key1 => subkey1 => integer ++的值? –

+1

@DavidWilliams(update-in my-map [:b] inc);; => {:a 1,:b 3} –

+0

明白了,這會創建一個新地圖,對嗎?我在想這會讓狀態更加艱難。例如,要創建貝葉斯分類器,我需要不斷地將事物的記錄更新爲多級結構。 key1 => subkey1 =>整數。我需要做som dosync和交換魔法嗎? –

7
(def my-map {:a 1 :b 2}) 
(zipmap (keys my-map) (map inc (vals my-map))) 
;;=> {:b 3, :a 2} 

要通過密鑰更新只有一個值:

(update-in my-map [:b] inc) ;;=> {:a 1, :b 3} 

由於Clojure的1.7它也可以使用update

(update my-map :b inc) 
2

要更新多個值,您還可以利用減少採取已填充的累加器,並在該集合和下列集合的每個成員上應用函數。

=> (reduce (fn [a k] (update-in a k inc)) {:a 1 :b 2 :c 3 :d 4} [[:a] [:c]]) 
{:a 2, :c 4, :b 2, :d 4} 

注意的關鍵需要被封閉在載體的,但你仍然可以做多更新插件像在原來的更新嵌套結構。

如果你做了它廣義函數,你可以通過與COLL ?:

(defn multi-update-in 
    [m v f & args] 
     (reduce 
     (fn [acc p] (apply 
         (partial update-in acc (if (coll? p) p (vector p)) f) 
         args)) m v)) 

這將允許單級/密鑰更新,而不需要在載體包裹按鍵測試它自動包裹在一個關鍵的載體

=> (multi-update-in {:a 1 :b 2 :c 3 :d 4} [:a :c] inc) 
{:a 2, :c 4, :b 2, :d 4} 

,但仍然能夠做到嵌套更新

(def people 
    {"keith" {:age 27 :hobby "needlefelting"} 
    "penelope" {:age 39 :hobby "thaiboxing"} 
    "brian" {:age 12 :hobby "rocket science"}}) 

=> (multi-update-in people [["keith" :age] ["brian" :age]] inc) 
    {"keith" {:age 28, :hobby "needlefelting"}, 
    "penelope" {:age 39, :hobby "thaiboxing"}, 
    "brian" {:age 13, :hobby "rocket science"}} 
0

我一直在玩弄同樣的想法,所以我想出了:

(defn remap 
    "returns a function which takes a map as argument 
    and applies f to each value in the map" 
    [f] 
    #(into {} (map (fn [[k v]] [k (f v)]) %))) 

((remap inc) {:foo 1}) 
;=> {:foo 2} 

(def inc-vals (remap inc)) 

(inc-vals {:foo 1}) 
;=> {:foo 2}