【问题标题】:Looping over dictionary recursively and remove keys递归遍历字典并删除键
【发布时间】:2017-01-05 20:07:59
【问题描述】:

我正在使用顶点和Data.Map 来尝试为跳棋游戏进行捕获动作。我正在使用函数 changeKey 更新地图中的当前键,并使用函数 cMove 进行捕获移动。现在,cMove 接受一个顶点、一个顶点列表(与对手的棋子)和一个包含顶点的地图和一个布尔值来指示棋子属于哪个玩家。 cMove 检查第一个顶点元组是否在地图中(以了解棋盘上的位置是否为空,因为计算会找到有效移动的位置)。如果是,changeKey 将被调用。

changeKey :: (Integer, Integer) -> (Integer, Integer) -> Map (Integer, Integer) Bool -> Map (Integer, Integer) Bool
changeKey k0 k1 myMap = case M.updateLookupWithKey (\_ _ -> Nothing) k0 myMap of
         (Nothing, _    ) -> myMap
         (Just e, myMap) -> M.insert k1 e myMap

cMove :: (Integer, Integer) -> [(Integer, Integer)] -> Map (Integer, Integer) Bool -> Map (Integer, Integer) Bool
cMove k [k1] myMap = if M.notMember (2*fst k1 - fst k, 2*snd k1 - snd k) myMap
                          then
                          changeKey k (2*fst k1 - fst k, 2*snd k1 - snd k) myMap
                          else myMap

我的问题在于,如果列表包含多个元组,我对如何循环遍历顶点列表一无所知(因为玩家每回合可以进行无限量的捕获)。此外,如何确保从地图中删除代表对手棋子的每个键。

【问题讨论】:

  • 您不应使用如下所示的函数调用:fst(k1)。您应该只使用fst k1,例如2*fst k1 - fst k
  • 已编辑。感谢您的反馈。
  • 从名字的拼写来看,ChangeKey不可能是函数。
  • 编辑修复changeKey大写。

标签: haskell dictionary recursion


【解决方案1】:

首先,the documentation for Data.Map 建议您在遇到这种情况时使用 Data.Map.Strict 而不是 Data.Map

此外,函数名称通常应以小写字母开头。


除此之外,在这里进行迭代的一种简单方法是将fold the elements of a list 转换为最终结果Map。您编写一个函数来处理一次迭代(参见下面的cMove'),然后使用foldrfoldl' 之类的东西让它为您完成所有迭代。

我不确定以下内容是否为您提供了您想要的行为,但这是使用foldr 的初稿:

import Data.Map.Strict (Map(..))
import qualified Data.Map.Strict as M

changeKey :: (Integer, Integer) -> (Integer, Integer) -> Map (Integer, Integer) Bool -> Map (Integer, Integer) Bool
changeKey k0 k1 myMap = case M.updateLookupWithKey (\_ _ -> Nothing) k0 myMap of
         (Nothing, _    ) -> myMap
         (Just e, myMap) -> M.insert k1 e myMap

cMove :: (Integer, Integer) -> [(Integer, Integer)] -> Map (Integer, Integer) Bool -> Map (Integer, Integer) Bool
cMove k ks myMap = foldr (cMove' k) myMap ks
  where
    cMove' :: (Integer, Integer) -> (Integer, Integer) -> Map (Integer, Integer) Bool -> Map (Integer, Integer) Bool
    cMove' k k1 myMap = if M.notMember (2*fst k1 - fst k, 2*snd k1 - snd k) myMap
                              then changeKey k (2*fst k1 - fst k, 2*snd k1 - snd k) myMap
                              else myMap

【讨论】:

  • 它正在到达那里。一个问题是,新的 k 没有用于列表的其余部分,但旧的 k 是。澄清一下,每当调用 changeKey 时,cMove 都应该使用新的顶点 k 而不是原来的。
  • 所以如果列表是[a, b, c, d, e],第一次应该使用ka,第二次使用abbc第三次,等等?
猜你喜欢
  • 2013-03-04
  • 2022-01-14
  • 2014-01-08
  • 2023-03-29
  • 1970-01-01
  • 2023-01-30
  • 2014-07-19
  • 2020-01-16
  • 1970-01-01
相关资源
最近更新 更多