Reputation: 647
I'm new to Clojure, and I have a nested map structured like this:
{:players
{"p1"
{:id "p1"
:deck []
:hand [{:name "Imp"
:entity-type :card}]
:minions [{:damage-taken 0
:attacks-performed-this-turn 0
:entity-type :minion
:name "Imp"
:id "m1"
:position 0
:owner-id "p1"}]
:hero
{:name "Jaina Proudmoore"
:id "h1"
:entity-type :hero
:mana 0
:damage-taken 0}}
etc
If I wanted to replace hero with an new map, one with all the same keys but different values, how could I do it? I've tried mapping the update function onto the keys of hero, but that hasn't worked.
Upvotes: 2
Views: 204
Reputation: 91554
there are two common functions for this, assoc-in for when you want to change one value and update-in
when you want to use a function to change the values based on the current value and or want to change several values:
user> (def players {:players
{"p1"
{:id "p1"
:deck []
:hand [{:name "Imp"
:entity-type :card}]
:minions [{:damage-taken 0
:attacks-performed-this-turn 0
:entity-type :minion
:name "Imp"
:id "m1"
:position 0
:owner-id "p1"}]
:hero
{:name "Jaina Proudmoore"
:id "h1"
:entity-type :hero
:mana 0
:damage-taken 0}}}})
#'user/players
In this case update-in
is a good match because it let's you do whatever you want to the nested collection. here's an example that assoc's some new values based on the previous ones, your could also add your function to map over the keys here as well.
user> (-> (update-in players [:players "p1" :hero]
#(assoc %
:name (str "long lost twin of " (:name %))
:id "h2"
:entity-type :antihero
:mana (inc (:mana %))
:damage-taken (dec (:damage-taken %))))
clojure.pprint/pprint)
{:players
{"p1"
{:id "p1",
:deck [],
:hand [{:name "Imp", :entity-type :card}],
:minions
[{:damage-taken 0,
:attacks-performed-this-turn 0,
:entity-type :minion,
:name "Imp",
:id "m1",
:position 0,
:owner-id "p1"}],
:hero
{:name "long lost twin of Jaina Proudmoore",
:id "h2",
:entity-type :antihero,
:mana 1,
:damage-taken -1}}}}
user>
Upvotes: 2