2013-03-19 2 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"}} 

Так что мой вопрос: Что такое наиболее идиоматических и правильный путь для достижения той же функциональности, как dicts 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:

Даже если ключ является переменной величиной (не компиляции постоянного времени) вы можете использовать как 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

Ах совершенны, 'Обновление-в' должен делать именно то, что я хочу (' ассоциативный в' был бы еще лучше, но я не знаю имя-ключа в 'vs' досрочно). По какой-то причине я не нахожу, чтобы документы были особенно ясными: я читал об «подключении» и «обновлении», но не понимал, как слить правильный ключ. Благодаря! – maxcountryman

+1

@maxcountryman - Незнание ключей/значений статически не является проблемой. См. Мои обновления для примеров использования нестатических ключей. – DaoWen

+0

Спасибо за обновление. Это может быть немного громоздким по сравнению с «обновлением» за то, что я делаю. Если мне нужно отделить ключ и значение с помощью 'assoc-in', код будет менее кратким, чем если бы я использовал' update-in', я думаю. Но хорошо видеть, что это можно сделать! – maxcountryman

Смежные вопросы