18
votes

If you have a map or a collection of maps and you'd like to be able to update the values of several keys with one function, what the the most idiomatic way of doing this?

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

Rather than mapping update-in for each key, I'd ideally like some function that operates like this:

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

Any advice would be much appreciated! I'm trying to reduce the number of lines in an unnecessarily long script.

1

1 Answers

28
votes

Whenever you need to iteratively apply a fn to some data, reduce is your friend:

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

Here it is in action:

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