Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 如何返回合并元组的列表?_Haskell - Fatal编程技术网

Haskell 如何返回合并元组的列表?

Haskell 如何返回合并元组的列表?,haskell,Haskell,目前我有一个元组列表[(1,[1]),(2,[1]),(3,[1]),(1,[2]),(3,[2]),(1,[3])。我想返回[(1,[1,2,3]),(2,[1]),(3,[1,2])的列表 我编写了一个合并两个元组的合并方法 merge :: Ord a => (a,[Int]) -> (a,[Int]) -> (a,[Int]) merge (x,y) (w,z) = (x, y ++ z ) 以及检查每个元组的第一个元素是否相等的方法 isEqual :: Ord a

目前我有一个元组列表[(1,[1]),(2,[1]),(3,[1]),(1,[2]),(3,[2]),(1,[3])。我想返回[(1,[1,2,3]),(2,[1]),(3,[1,2])的列表

我编写了一个合并两个元组的合并方法

merge :: Ord a => (a,[Int]) -> (a,[Int]) -> (a,[Int])
merge (x,y) (w,z) = (x, y ++ z )
以及检查每个元组的第一个元素是否相等的方法

isEqual :: Ord a => (a,[Int]) -> (a,[Int]) -> Bool
isEqual (x,y) (w,z)
  | x == w = True
  | otherwise = False

我很难想出一种方法来对每个元素运行isEqual和merge方法,尽管这样可以得到答案。你们推荐折叠法还是递归法?谢谢

一般来说,要有效地解决这类问题,需要将值存储在映射结构中,以便通过匹配的“键”轻松访问。这样,当您遇到
(1,[2])
时,您可以快速查阅地图,查看您已经有
(1,[1])
,并将它们组合起来得到
(1,[1,2])
。稍后,当您遇到
(1,[3])
时,您可以在地图中快速找到
(1,[1,2])
,并将它们组合以获得
(1,[1,2,3])
,依此类推

对于这个特定的问题,有一个简短的解决方案,使用
Data.Map
中的工具:

import qualified Data.Map.Strict as Map

gather :: (Ord a) => [(a, [Int])] -> [(a, [Int])]
gather = Map.toList . Map.fromListWith (++) . reverse
之后:

> gather [(1 , [1]) , (2 , [1]) , (3 , [1]) , (1 , [2]) , (3 , [2]) , (1 , [3])]
[(1,[1,2,3]),(2,[1]),(3,[1,2])]
这里,
Map.fromListWith
运行键值对列表
[(k,v)]
,并将它们逐个添加到新映射中。添加每一对时,如果密钥不在映射中,则会在该密钥下添加值(在您的情况下,是一个单例值,如
[1]
[2]
)。如果键已在映射中,则使用提供的函数
(++)
(即,作为
新的\u单例\u值++现有的\u值列表
)将新值与旧值组合。这样做的效果是从输入列表中以相反的顺序创建一个值列表,因此我使用
reverse
对输入列表进行了预处理。(如果订单不重要,你应该放弃。)

此问题的一个更常见的变体是编写一个函数,该函数包含一组对:

[(1,1), (2,1), (3,1), (1,2), (3,2), (1,3)]

其中的值尚未列出。解决办法是一样的。您只需使用
map(\(k,v)->(k,[v])
对列表进行预处理。此解决方案包含在注释中提到的解决方案中。

简单(且高效)方法是浏览
Data.Map.fromListWith
或者,看看这是否回答了您的问题?我投票将此问题作为主题外的问题结束,因为堆栈溢出不是一种代码编写服务。