2013-03-19 14 views
6

że mamy mapę, która wygląda mniej więcej tak:Idiomatyczny sposób "aktualizacji" danego klucza w mapie Clojure?

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

Teraz chcielibyśmy, aby zaktualizować klucz: a W M z nowymi wartościami:

(def vs {:baz "qux"}) 

Gdyby to było Python mogliśmy zrobić coś takiego:

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

najprostszym Clojure ekwiwalentu znalazłem było zdefiniować funkcję tak:

(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))) 

który następnie jest wywoływany jak:

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

Więc moje pytanie brzmi: Co jest najbardziej idiomatyczne i prawidłowy sposób, aby osiągnąć tę samą funkcjonalność jak dicts update() metoda Python dostarczyć?

Odpowiedz

10

myślę szukasz 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 jest podobna, a może warto patrząc na zbyt. To może być rzeczywiście bliżej przykład Python:

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

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

Aktualizacja:

Nawet jeśli klucz jest wartość zmiennej (a nie kompilacji stała) nadal można używać zarówno update-in i assoc-in poprzez umieszczenie zmiennej w wektorze:

(def m {:a {:foo "bar"}}) 
(def k' :baz) 
(def v' "qux") 

(assoc-in m [:a k'] v') 
; => {:a {:foo "bar", :baz "qux"}} 

można także zbudować klucze wektor programowo:

(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

Ah doskonały, 'update-in' powinni robić dokładnie to, co chcę (' doc-in' byłoby jeszcze lepiej, ale nie wiem, nazwa-klucz w 'vs' z wyprzedzeniem). Z jakiegoś powodu nie znajduję dokumentów, które mogłyby być szczególnie pomocne w wyjaśnieniu: przeczytałem o "assoc-in" i "update-in", ale nie rozumiałem, jak połączyć się z właściwym kluczem. Dzięki! – maxcountryman

+1

@maxcountryman - Brak znajomości klawiszy/wartości statycznie nie stanowi problemu. Zobacz moje aktualizacje na przykłady użycia kluczy niestacjonarnych. – DaoWen

+0

Dzięki za aktualizację. To może być trochę kłopotliwe w porównaniu do 'update-in' dla tego, co robię. Jeśli będę musiał oddzielić klucz i wartość za pomocą 'assoc-in', kod będzie mniej zwięzły niż w przypadku użycia' update-in'. Ale dobrze jest zobaczyć, jak można to zrobić! – maxcountryman

Powiązane problemy