如何使用clojure中的函数替换嵌套映射中的多个值?

时间:2018-11-08 16:10:38

标签: dictionary clojure immutability

我是Clojure的新手,我有一个嵌套的地图,其结构如下:

{: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

如果我想用一张新地图替换英雄,那张地图的所有键都相同但值不同,我该怎么办?我尝试将更新功能映射到hero的键上,但这没有用。

1 个答案:

答案 0 :(得分:2)

有两个常见的函数,当您想更改一个值时,使用ascoc-in;当您要使用函数根据当前值更改值,或想更改多个值时,使用update-in值:

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

在这种情况下,update-in是一个很好的选择,因为它使您可以对嵌套集合进行任何操作。这是一个示例,它根据先前的值分配了assoc的一些新值,您也可以添加函数来映射此处的键。

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>