Imagine you have a map like this:
(def person { :name { :first-name "John" :middle-name "Michael" :last-name "Smith" }})
What is the idiomatic way to change values associated with both :first-name and :last-name in one expression?
(Clarification: Let's say you want to set :first-name to "Bob" and :last-name to "Doe". Let's also say that this map has some other values in it that we want to preserve, so constructing it from scratch is not an option)
Here are a couple of ways.
user> (update-in person [:name] assoc :first-name "Bob" :last-name "Doe") {:name {:middle-name "Michael", :last-name "Doe", :first-name "Bob"}} user> (update-in person [:name] merge {:first-name "Bob" :last-name "Doe"}) {:name {:middle-name "Michael", :last-name "Doe", :first-name "Bob"}} user> (update-in person [:name] into {:first-name "Bob" :last-name "Doe"}) {:name {:middle-name "Michael", :last-name "Doe", :first-name "Bob"}} user> (-> person (assoc-in [:name :first-name] "Bob") (assoc-in [:name :last-name] "Doe")) {:name {:middle-name "Michael", :last-name "Doe", :first-name "Bob"}}
update-in
does recursive assoc
s on your map. In this case it's roughly equivalent to:
user> (assoc person :name (assoc (:name person) :first-name "Bob" :last-name "Doe"))
The repetition of keys becomes more and more tedious as you go deeper into a series of nested maps. update-in
's recursion lets you avoid repeating keys (e.g. :name
) over and over; intermediary results are stored on the stack between recursive calls. Take a look at the source for update-in to see how it's done.
user> (def foo {:bar {:baz {:quux 123}}}) #'user/foo user> (assoc foo :bar (assoc (:bar foo) :baz (assoc (:baz (:bar foo)) :quux (inc (:quux (:baz (:bar foo))))))) {:bar {:baz {:quux 124}}} user> (update-in foo [:bar :baz :quux] inc) {:bar {:baz {:quux 124}}}
assoc
is dynamic (as are update-in
, assoc-in
, and most other Clojure functions that operate on Clojure data structures). If assoc
onto a map, it returns a map. If you assoc
onto a vector, it returns a vector. Look at the source for assoc and take a look in in RT.java
in the Clojure source for details.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With