2

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.

5
  • 4
    Possible duplicate of Clojure nested map - change value Commented Nov 8, 2018 at 16:14
  • 1
    Tl;DR: Don't map update. Use update-in or assoc-in. Commented Nov 8, 2018 at 17:17
  • this is slightly different than the question above, because it's about how to update multiple keys, and the answers there don't show the efficient way to do this particular thing. I'll edit the title here to make the differences clear Commented Nov 8, 2018 at 18:07
  • 2
    @JaredSmith : Arthur is correct, I should've made it clearer Commented Nov 8, 2018 at 18:14
  • Close vote retracted Commented Nov 8, 2018 at 18:22

1 Answer 1

2

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> 
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.