Reputation: 531
I am wondering how to update two values at the same time. For instance, I want to increase month and decrease age at the same time. My code is
user=>(def users {:month 1 :age 26})
user=>(update-in users [:month :age] inc dec)
I know this syntax is not correct, but how can I fix this? And I need to update at the same time. Since if I update month first and then update age, then the first map will lost when I update the second map. Or is there other way to figure out this problem?
Upvotes: 1
Views: 375
Reputation: 13473
I'm tempted to solve this problem generally, by writing a function that takes a map: keyword -> function, and turns out a function that applies all the functions to the relevant record/map entries.
Such a function is
(defn field-updater [fn-map]
(fn [record]
(reduce
(fn [m [k f]] (assoc m k (f (m k))))
record
fn-map)))
And we use it to generate your required field updater:
(def update-in-users (field-updater {:month inc :age dec}))
... which we can then apply
(update-in-users users)
;{:month 2, :age 25}
Upvotes: 0
Reputation: 17859
in this simple case (update functions without additional params) you could also do it like this:
user> (def users {:month 1 :age 26 :records [1 2 3]})
#'user/users
user> (reduce-kv update users {:month inc :age dec :records reverse})
{:month 2, :age 25, :records (3 2 1)}
with additional params it would be a little bit more verbose:
user> (reduce-kv (partial apply update)
users
{:month [+ 2] :age [dec] :records [conj 101]})
{:month 3, :age 25, :records [1 2 3 101]}
well, it is still worse then simple usage of threading macro.
Upvotes: 2
Reputation: 17773
update
does not modify a value, it just returns a new value, so it's just a function. If you need to update 2 fields of a map, the straightforward way to do that is just call update
twice, first on the original map and then on the result of the first update:
(defn update-month-and-age [user]
(update (update user :month inc) :age dec))
Which looks nicer using ->
:
(defn update-month-and-age [user]
(-> user
(update :month inc)
(update :age dec)))
Upvotes: 5