2012-03-09 18 views
13

Se si dispone di una mappa o di una raccolta di mappe e si desidera poter aggiornare i valori di più tasti con una funzione, qual è il modo più idiomatico per farlo?Aggiornare i valori di più chiavi

=> (def m [{:a 2 :b 3} {:a 2 :b 5}]) 
#'user/m 
=> (map #(update-in % [:a] inc) m) 
({:a 3, :b 3} {:a 3, :b 5}) 

Invece di mappatura update-in per ogni tasto, mi piacerebbe idealmente come una funzione che opera in questo modo:

=> (map #(update-vals % [:a :b] inc) m) 
({:a 3, :b 4} {:a 3, :b 6}) 

Qualche consiglio sarebbe molto apprezzato! Sto cercando di ridurre il numero di righe in uno script inutilmente lungo.

risposta

22

Ogni volta che è necessario applicare in modo iterativo un fn ad alcuni dati, reduce è tuo amico:

(defn update-vals [map vals f] 
    (reduce #(update-in % [%2] f) map vals)) 

Eccolo in azione:

user> (def m1 {:a 2 :b 3}) 
#'user/m1 
user> (update-vals m1 [:a :b] inc) 
{:a 3, :b 4} 
user> (def m [{:a 2 :b 3} {:a 2 :b 5}]) 
#'user/m 
user> (map #(update-vals % [:a :b] inc) m) 
({:a 3, :b 4} {:a 3, :b 6}) 
+1

Molto bello, grazie per la risposta rapida anche! – Giles

+0

Mi chiedo se c'è un modo per mantenere il comportamento di update-in in modo che una chiave mancante non generi un'eccezione di puntatore nullo. '(update-in {} [: test] (fnil inc 0)) {: test 1}' – Istvan

+0

questa è una risposta molto piacevole e mette in risalto parte della bellezza dell'apprendimento del clojure (anche alcune delle difficoltà del cervello ad non-lisper) – zach

Problemi correlati