使用assoc-in永久更改地图Clojure中的值

时间:2016-02-18 18:22:13

标签: dictionary clojure

对于大量的问题感到抱歉。

我有一张卡片地图:

    (def cards
  {
    :card1 {:name "Wisp"              :type "Monster"     :damage 1   :health 1   :cost 0   :ability 0 :active true}
    :card2 {:name "Spider Tank"       :type "Monster"     :damage 3   :health 4   :cost 3   :ability 0 :active true}
    :card3 {:name "Boulder Fist Ogre" :type "Monster"     :damage 6   :health 7   :cost 6   :ability 0 :active true}
    :card4 {:name "Bloodfen Raptor"   :type "Monster"     :damage 3   :health 2   :cost 2   :ability 0 :active true}
    :card5 {:name "Chillwind Yeti"    :type "Monster"     :damage 4   :health 5   :cost 4   :ability 0 :active true}
    :card6 {:name "Magma Rager"       :type "Monster"     :damage 5   :health 1   :cost 3   :ability 0 :active true}
    :card7 {:name "War Golem"         :type "Monster"     :damage 7   :health 7   :cost 7   :ability 0 :active true}
    :card8 {:name "Oasis Snapjaw"     :type "Monster"     :damage 2   :health 7   :cost 4   :ability 0 :active true}
    :card9 {:name "River Crocolisk"   :type "Monster"     :damage 2   :health 3   :cost 2   :ability 0 :active true}
    :card10 {:name "Murloc Raider"    :type "Monster"     :damage 2   :health 1   :cost 1   :ability 0 :active true}
    :card11 {:name "Northshire Cleric":type "Monster"     :damage 1   :health 3   :cost 1   :ability 2 :active true}
    :card12 {:name "Nat Peagle"       :type "Monster"     :damage 0   :health 4   :cost 2   :ability 4 :active true}
    :card13 {:name "Molten Giant"     :type "Monster"     :damage 8   :health 8   :cost 20  :ability 0 :active true}
    }
 )

这些卡片列在我的董事会名单中:

(def board1 (list (:card3 cards) (:card4 cards) (:card11 cards) nil nil nil nil))

我想要做的是将卡上的活动标志从true更改为false。

我知道我可以直接通过以下方式对我的卡片收集进行此操作:

user=> (assoc-in (:card11 cards) [:active] false)
{:ability 2, :name "Northshire Cleric", :type "Monster", :damage 1, :active false, :health 3, :cost 1}

我试图建立一个功能,当给出一个集合(板)和一个数字(第n)卡。使此板中的此卡永久伪造。

我一直在尝试原子,但到目前为止还没有快乐。

(test-function board1 1)

(defn test-function [coll number]
  (let [test (atom coll)]
    (swap! test assoc-in (get (nth @test number)) [:active] false)
    (println test)))

我想知道我做错了什么,以及是否有一种更简洁的方法可以在不使用原子的情况下做到这一点。

2 个答案:

答案 0 :(得分:2)

您需要在let块之外声明您的原子。你拥有它的方式,你每次都重新绑定它。 atom是状态事物的好选择,所以声明你的原子是这样的:

(def cards (atom
  {:card1 {:name "Wisp" :active true}
   :card2 {:name "Spider Tank" :active true}}))

然后你可以编写你的函数来交换false,如下所示:

(defn myfunc [coll number]
  (swap! coll assoc-in [(str :card number) :active] false ))

您不需要两个不同的功能,一个用于设置为true,另一个用于设置为false。你应该采取下一步,让它读取当前的布尔值,然后assoc-in相反的值。 (另请注意,我保留了样本数据样本非常小)。 ;)

答案 1 :(得分:2)

JT93

根据您的评论,您希望取消atom并采用干净的更新方法。

如果您可以在问题中提供更多信息,请永久澄清您的意思。例如:您是否希望在执行的整个生命周期内保持电路板状态?如果是这样,您可能需要使用atom,尽管Clojure还有一些不同的方法。

首先,考虑将board1的定义更改为向量而不是列表。然后你可以放弃使用神秘逻辑,只需轻轻一点地使用assoc-in

(def board1 [(:card3 cards) (:card4 cards) (:card11 cards) nil nil nil nil])

(defn test-function [coll number]
    (assoc-in coll [number :active] false))

(clojure.pprint/pprint (test-function board1 0))