在 Clojure 中使用 disj 从集合中删除元素

问题描述 投票:0回答:5

嗨,我在尝试从集合中删除元素时遇到了困难。

我有一张卡片地图。

   (def cards
  {
    :card1 {:name "Wisp"              :type "Monster"     :damage 1 :health 1 :cost 0 :charge "t"}
    :card2 {:name "Spider Tank"       :type "Monster"     :damage 3 :health 4 :cost 3}
    :card3 {:name "Boulder Fist Ogre" :type "Monster"     :damage 6 :health 7 :cost 6}

    }
 )

还有一副(套)这些卡片。

(def deck1 (set (map cards '(:card1 :card2 :card3))))

当我使用 disj 尝试删除其中一张卡时,没有任何反应。

(disj deck1 :card1)

我真的不知道为什么。

clojure set
5个回答
3
投票

leetwinski 的评论是正确的。

(disj deck1 (:card1 cards))
是正确的。


1
投票

您可以避免将其变成集合,只需使用

dissoc
即可。 Dissoc 在地图而不是集合上工作,因此您可以避免额外的类型转换。

user=> (dissoc cards :card1)
{:card2 {:name "Spider Tank", :type "Monster", :damage 3, :health 4, :cost 3},
 :card3 {:name "Boulder Fist Ogre", :type "Monster", :damage 6, :health 7, :cost 6}}

1
投票

首先,这不是典型的 clojure 习惯用法:

'(:card1 :card2 :card3)

这更容易、更干净:

[:card1 :card2 :card3]

其次,在我看来,你的收藏有点复杂化了。正如其他评论中所述,您不能

disj
不在那里的钥匙;您的
map
函数返回与键
:card1
等关联的值,因此尝试在结果上删除键将不会执行任何操作。

现在,只有当您期望原始映射中的值可能在该映射中重复时,将其转换为集合这一事实才重要。是否有可能拥有多张具有相同伤害的 Wisp 卡等?例如,如果 :card5 和 :card8 可能是相同的值,则将映射转换为集合将删除这些重复项。如果卡牌不可能相同,那么地图已经具有无法复制的唯一键,因此我不确定将其转换为一组会获得什么。


1
投票

deck1

#{{:name "Wisp", :type "Monster", :damage 1, :health 1, :cost 0, :charge "t"}
  {:name "Spider Tank", :type "Monster", :damage 3, :health 4, :cost 3}
  {:name "Boulder Fist Ogre", :type "Monster", :damage 6, :health 7, :cost 6}}

此集合不包含

:card1
。所以
(disj deck1 :card1)
没有任何作用。

你想要类似的东西

(apply disj deck1 (filter #(= (:name %) "Wisp") deck1))

...删除所有带有

:name
"Wisp"
的元素 - 只有一个,给出

#{{:name "Spider Tank", :type "Monster", :damage 3, :health 4, :cost 3}
  {:name "Boulder Fist Ogre", :type "Monster", :damage 6, :health 7, :cost 6}}

0
投票

另一种选择是保留单独的 def

(def available-cards #{:card1 :card2 :card3})
。那么你就不是在寻找一个大的物体作为钥匙。如果您的卡片由于某些其他原因随着时间的推移而发生变化,那么您并不依赖于集合中匹配的卡片对象。

© www.soinside.com 2019 - 2024. All rights reserved.