Search code examples
clojure

Update the values of multiple keys


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.


Solution

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