我在Clojure周围环绕着我的头。我来自可以改变国家的语言。例如,在Python中,我可以创建一个字典,放一些string =>内部的整数对,然后遍历字典并递增值。
我如何在惯用的Clojure中做到这一点?
答案 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 %)))