2013-03-19 46 views
6

說我們有一個地圖,看起來像:在Clojure地圖中更新給定密鑰的習慣方式?

(def m {:a {:foo "bar"}}) 

現在,我們想更新的關鍵是:在一米,一些新的價值觀:

(def vs {:baz "qux"}) 

如果這是Python中我們可以這樣做:

>>> d = {'a': {'foo': 'bar'}} 
>>> d['a'].update({'baz': 'qux'}) 
>>> d 
{'a': {'foo': 'bar', 'baz': 'qux'}} 

最簡單的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))) 

然後調用,如:

(update-key :a m vs) 
; => {:a {:foo "bar" :baz "qux"}} 

所以我的問題是:什麼是最地道的,正確的方式來實現相同的功能的update()方法的Python類型的字典提供?

回答

10

我認爲你正在尋找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"}} 

update-in是相似的,而且可能是值得考慮的太多。這實際上可能是更接近你的Python的例子:

(def m {:a {:foo "bar"}}) 
(def vs {:baz "qux"}) 

(update-in m [:a] merge vs) 
; => {:a {:foo "bar", :baz "qux"}} 

更新:

即使關鍵是一個變量值(不是編譯時間常數),你仍然可以使用這兩個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"}} 

您也可以建立個鍵矢量編程:

(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"}} 
+0

完美啊,'更新in'應該做的正是我想要的('assoc命令-in'甚至會更好,但我不知道'vs'密鑰名提前時間)。出於某種原因,我沒有發現文檔要特別說明:我已經閱讀了關於'assoc-in'和'update-in',但不知道如何合併到正確的密鑰中。謝謝! – maxcountryman 2013-03-19 23:48:59

+1

@maxcountryman - 靜態不知道鍵/值不是問題。有關使用非靜態鍵的示例,請參閱我的更新。 – DaoWen 2013-03-20 02:20:30

+0

感謝您的更新。與我正在做的事情的'update-in'相比,這可能有點麻煩。如果我必須用'assoc-in'分隔鍵和值,那麼代碼將不如我使用'update-in'簡潔。但很高興看到它可以完成! – maxcountryman 2013-03-20 04:13:12

相關問題