如何增加地图中的值

时间:2013-04-13 21:36:49

标签: clojure state immutability

我在Clojure周围环绕着我的头。我来自可以改变国家的语言。例如,在Python中,我可以创建一个字典,放一些string =>内部的整数对,然后遍历字典并递增值。

我如何在惯用的Clojure中做到这一点?

5 个答案:

答案 0 :(得分:8)

(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)

答案 1 :(得分:3)

只需produce新地图并使用它:

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

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

; {:b 5, :a 4}

答案 2 :(得分:2)

要更新多个值,您还可以利用reduce对已经填充的累加器进行操作,并对该对象和以下集合的每个成员应用一个函数。

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

答案 3 :(得分: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}

答案 4 :(得分:0)

稍微改善@Michiel Brokent的答案。如果密钥不存在,这将起作用。

(update my-map :a #(if (nil? %) 1 (inc %)))