2013-03-19 1 views
6

Supponiamo di avere una mappa che sembra qualcosa di simile:Modo idiomatico di "aggiornamento" di una determinata chiave in una mappa di Clojure?

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

Ora vorremmo aggiornare la chiave: un in m con alcuni nuovi valori:

(def vs {:baz "qux"}) 

Se questo fosse Python potremmo fare qualcosa di simile:

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

Il più semplice Clojure equivalente che ho trovato è stato quello di definire una funzione come questa:

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

che viene poi richiamato come:

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

Quindi la mia domanda è: Qual è il modo più idiomatica e corretta per ottenere la stessa funzionalità delle dicts update() metodo Python forniscono?

risposta

10

Penso che tu sia alla ricerca di 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 è simile, e potrebbe essere la pena di guardare troppo. Questo potrebbe in realtà essere più vicino al tuo Python esempio:

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

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

Aggiornamento:

Anche se la chiave è un valore variabile (non una fase di compilazione costante) è comunque possibile utilizzare sia update-in e assoc-in mettendo la variabile nel vettore:

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

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

Si può anche costruire il chiavi vettore programmaticamente:

(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 perfetto, 'update-tale dicitura deve fare esattamente quello che voglio (' assoc-tale dicitura sarebbe ancora meglio, ma non so il nome-chiave in 'vs' in anticipo). Per qualche ragione, non sto trovando i documenti particolarmente illuminanti: avevo letto sia su 'assoc-in' che su' update-in' ma non ho capito come unire la chiave corretta. Grazie! – maxcountryman

+1

@maxcountryman: non conoscere le chiavi/i valori in modo statico non è un problema. Vedi i miei aggiornamenti per esempi sull'uso di chiavi non statiche. – DaoWen

+0

Grazie per l'aggiornamento. Questo potrebbe essere un po 'macchinoso rispetto a "update-in" per quello che sto facendo. Se devo separare la chiave e il valore con 'assoc-in', il codice sarà meno conciso di quello che uso se si usa' update-in'. Ma è bello vedere che si può fare! – maxcountryman