我正在尝试使用Clojure的update-in函数,但我似乎无法理解为什么需要传入函数?
答案 0 :(得分:30)
update-in
接受一个函数,因此您可以更简洁地更新给定位置的值,具体取决于旧值。例如,而不是:
(assoc-in m [list of keys] (inc (get-in m [list of keys])))
你可以写:
(update-in m [list of keys] inc)
当然,如果新值不依赖于旧值,assoc-in
就足够了,您无需使用update-in
。
答案 1 :(得分:5)
这不是你问题的直接答案,但是像update-in
这样的函数可能存在的一个原因是为了效率 - 而不仅仅是方便 - 如果它能够更新地图中的值“ -地点”。也就是说,而不是
可以想象一种算法可以省略对密钥的第二次搜索:
不幸的是,the current implementation of update-in
没有执行此“就地”更新。它使用get
进行提取,使用assoc
进行替换。除非assoc
正在使用最后一个查找键和相应的键值元组的某些缓存,否则对assoc
的调用将不得不再次寻找密钥。
答案 2 :(得分:3)
我认为简短的回答是传递给update-in的函数允许您在一个步骤中更新值,而不是3(查找,计算新值,设置)。
巧合的是,就在今天,我在Howard Lewis Ship的Clojure演讲中遇到过update-in的使用:
(def in-str "this is this")
(reduce
(fn [m k] (update-in m [k] #(inc (or % 0))))
{}
(seq in-str))
==> {\space 2, \s 3, \i 3, \h 2, \t 2}
每次调用update-in都会将一个字母作为键,在地图中查找,如果找到则会增加字母数(或者将其设置为1)。 reduce通过以空映射{}开始驱动进程,并使用输入字符串中的连续字符重复应用update-in。结果是字母频率图。光滑。
注1:clojure.core /频率相似但使用了assoc!而不是更新。
注2:您可以用(fnil inc 0)替换#(inc(或%0))。从这里开始:fnil
答案 3 :(得分:1)
您看到here的实际示例。
输入此代码段(在您的REPL中):
(def my-map {:useless-key "key"})
;;{:useless-key "key"}
(def my-map (update-in my-map [:yourkey] #(cons 1 %)))
;;{:yourkey (1), :useless-key "key"}
请注意:yourkey
是新的。因此传递给lambda的:yourkey
- 的值是null
。 cons
会将1
作为您列表中的单个元素。现在执行以下操作:
(def my-map (update-in my-map [:yourkey] #(cons 25 %)))
;;{:yourkey (25 1), :useless-key "key"}
就是这样,在第二部分中,匿名函数将列表 - 值为:yourkey - 作为参数,只是对它有利。
由于我们的my-map
是不可变的,update-in
将始终返回您的地图的新版本,让您使用给定密钥的旧值执行某些操作。
希望它有所帮助!