【问题标题】:Changing the value in a tuple of tuples conditionally in Haskell在 Haskell 中有条件地更改元组中的值
【发布时间】:2015-09-25 16:36:58
【问题描述】:

我正在处理 3 元组中的 3 元组 ((a,b,c),(d,e,f),(g,h,i))。现在我想把这个元组作为输入,并作为输出生成一个元组列表,其中一个元素如果具有某个值,就会更改为一个值。

例子:

changefromtovalue :: a -> a -> ((a,a,a),(a,a,a),(a,a,a)) -> [((a,a,a),(a,a,a),(a,a,a))]

changefromtovalue 1 5 ((0,1,2),(1,2,3),(2,3,4)) results in [((0,5,2),(1,2,3),(2,3,4)),((0,1,2)(5,2,3)(2,3,4))]

现在我不使用整数,但我认为这个想法保持不变。

首先我想我想要某种地图,但这会立即更改所有值,而不是制作一个每个更改一个元素的列表。

然后我想,我可以做出所有变化(在示例中 [((5,x,x)..),((x,5,x)..),((x,x,5)..)] 并以某种方式删除不符合要求的那些,但我无法找到一种干净的方法来删除不需要的那些。

我尝试搜索并找到了一些有关为元组制定数据规范的信息,但我看不出这将如何真正简化这个特定问题。

转换为列表并使用列表然后再转换回来似乎更容易,但它仍然需要一种奇怪的选择。如果可能的话,我想避免使用大量的转换。

我正在寻找的是一个导致一种干净的方式的建议,而不是一个完整的代码行。

【问题讨论】:

  • 你需要这个笨重的类型做什么?该任务是否允许用更方便的东西替换它?
  • 是的,但我看不出将((a,b,c),(d,e,f),(g,h,i)) 转换为[a,b,c,d,e,f,g,h,i][[a,b,c],[d,e,f],[g,h,i]] 会如何使这项特定任务更容易。

标签: list haskell tuples element


【解决方案1】:

借助您在评论中提供的其他信息,我们可以使用 Richard Bird 的方法解决此问题:

我们将网格表示为列表列表。然后,我们将网格中的每个元素替换为我们可以为它做出的选择列表。在您的示例中,1 变为 [1,5](我们选择 1 或 5),n 变为 [n](对于其他所有内容,没有其他选择)。

choice                :: Int -> [Int]
choice 1              =  [1,5]
choice n              =  [n]

然后我们为每个元素做出这样的选择:

choices               :: [[Int]] -> [[[Int]]]
choices               =  map (map choice)

现在是棘手的部分。我们将选择网格简化为选择网格,这可以使用列表的一般笛卡尔积来完成:

cp                    :: [[a]] -> [[a]]
cp []                 =  [[]]
cp (xs:xss)           =  [y:ys | y <- xs, ys <- cp xss]

我们像这样折叠一个选择网格:

collapse              :: [[[a]]] -> [[[a]]]
collapse              =  cp . map cp

首先将选择行列表(也称为选择网格)折叠成行选择列表,然后将行选择列表折叠成行列表选择,也就是网格选择.

最后,我们通过首先做出选择然后折叠它们来指定求解器:

solve                 :: [[Int]] -> [[[Int]]]
solve                 =  collapse . choices

例如:

> mapM_ print (solve [[0,1,2],[1,2,3],[2,3,4]])

[[0,1,2],[1,2,3],[2,3,4]]
[[0,1,2],[5,2,3],[2,3,4]]
[[0,5,2],[1,2,3],[2,3,4]]
[[0,5,2],[5,2,3],[2,3,4]]

希望这也展示了将元组转换为列表列表如何使这项任务更容易。


注意:有些人可能已经注意到 cpsequence 用于列表应用程序。这意味着我们也可以等价地写:

solve' = sequence . map sequence . choices

【讨论】:

  • 这可能会起作用并阅读您的解决方案我找到了自己的解决方案。对于有兴趣的人,我会写在答案中。
  • solve' 也可以写成traverse (traverse choice),完全跳过choices,同时泛化类型以允许每个表表示为,例如,向量的向量,甚至是数组。
【解决方案2】:

使用元组你必须写:

change x y ((a,b,c),(d,e,f),(g,h,i))
     = ((z a, z b, z c), (z d, z e, z f), (z g, z h, z i))
  where z w = if w == x then y else w

如果您使用列表(或数组)来表示您的 3x3 网格,生活会更轻松。

【讨论】:

  • 这会将所有 x 更改为 y 并给我一个新元组,我想更改单个 x 并将每个更改的元组添加到列表中。
猜你喜欢
  • 1970-01-01
  • 2022-11-25
  • 2021-07-03
  • 1970-01-01
  • 1970-01-01
  • 2019-09-11
  • 2018-08-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多