假设我们有一张类似于的地图:
(def m {:a {:foo "bar"}})
Run Code Online (Sandbox Code Playgroud)
现在我们要更新密钥:一个带有一些新值的m:
(def vs {:baz "qux"})
Run Code Online (Sandbox Code Playgroud)
如果这是Python,我们可以做类似的事情:
>>> d = {'a': {'foo': 'bar'}}
>>> d['a'].update({'baz': 'qux'})
>>> d
{'a': {'foo': 'bar', 'baz': 'qux'}}
Run Code Online (Sandbox Code Playgroud)
我发现最简单的Clojure等价物是定义一个这样的函数:
(defn update-key
"
Updates a given key `k` over a map `m` with a map of values `vs`.
"
[k m vs]
(assoc m k (merge (k m) vs)))
Run Code Online (Sandbox Code Playgroud)
然后调用如下:
(update-key :a m vs)
; => {:a {:foo "bar" :baz "qux"}}
Run Code Online (Sandbox Code Playgroud)
所以我的问题是:实现与update()Python dicts提供的方法相同的功能的最惯用和最正确的方法是什么?
Dao*_*Wen 11
我想你正在寻找assoc-in:
(def m {:a {:foo "bar"}})
(assoc-in m [:a :foo] "qux")
; => {:a {:foo "qux"}}
(assoc-in m [:a :baz] "qux")
; => {:a {:foo "bar", :baz "qux"}}
Run Code Online (Sandbox Code Playgroud)
update-in是类似的,也可能值得一看.这实际上可能更接近您的Python示例:
(def m {:a {:foo "bar"}})
(def vs {:baz "qux"})
(update-in m [:a] merge vs)
; => {:a {:foo "bar", :baz "qux"}}
Run Code Online (Sandbox Code Playgroud)
更新:
即使关键是一个变量值(不是编译时间常数),你仍然可以同时使用update-in,并assoc-in通过将变量向量:
(def m {:a {:foo "bar"}})
(def k' :baz)
(def v' "qux")
(assoc-in m [:a k'] v')
; => {:a {:foo "bar", :baz "qux"}}
Run Code Online (Sandbox Code Playgroud)
您还可以以编程方式构建键向量:
(def m {:a {:foo "bar"}})
(def k' :baz)
(def v' "qux")
(let [ks (conj [:a] k')]
(assoc-in m ks v'))
; => {:a {:foo "bar", :baz "qux"}}
Run Code Online (Sandbox Code Playgroud)