简体   繁体   English

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

[英]How do I return a list of merged tuples?

Currently I have a list of tuples [ (1 , [1]) , (2 , [1]) , (3 , [1]) , (1 , [2]) , (3 , [2]) , (1 , [3]) ].目前我有一个元组列表 [ (1 , [1]) , (2 , [1]) , (3 , [1]) , (1 , [2]) , (3 , [2]) , (1 , [3]) ]。 I'd like to return a list of [ (1 , [1,2,3]) , (2 , [1]) , (3 , [1,2]) ].我想返回 [ (1 , [1,2,3]) , (2 , [1]) , (3 , [1,2]) ] 的列表。

I have written a merge method that merges two tuples.我编写了一个合并两个元组的合并方法。

merge :: Ord a => (a,[Int]) -> (a,[Int]) -> (a,[Int])
merge (x,y) (w,z) = (x, y ++ z )

And a method that checks if the first element of each tuple is equal.以及检查每个元组的第一个元素是否相等的方法。

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

I'm having trouble coming up with a way to run the isEqual and merge methods on each element though to get to the answer.我在想出一种在每个元素上运行 isEqual 和 merge 方法的方法时遇到了麻烦,但为了得到答案。 Would you guys recommend a fold or a recursive method?你们会推荐折叠方法还是递归方法? Thanks!谢谢!

Generally, to solve this type of problem efficiently , you need to store the values in a map structure that can be easily accessed by the "key" on which you're matching.通常,要有效地解决此类问题,您需要将值存储在地图结构中,该结构可以通过您匹配的“键”轻松访问。 That way, when you run across (1, [2]) , you can quickly consult the map, see that you already have (1, [1]) , and combine them to get (1, [1,2]) .这样,当你遇到(1, [2]) ,你可以快速查阅地图,看到你已经有了(1, [1]) ,并将它们组合起来得到(1, [1,2]) Later, when you run across (1, [3]) , you can quickly find (1, [1,2]) in the map and combine them to get (1, [1,2,3]) , and so on...之后,当你跑到(1, [3]) ,你可以在地图中快速找到(1, [1,2])并将它们组合起来得到(1, [1,2,3]) ,依此类推...

For this specific problem, there's a short solution using facilities in Data.Map :对于这个特定问题,有一个使用Data.Map的工具的简短解决方案:

import qualified Data.Map.Strict as Map

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

after which:之后:

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

Here, Map.fromListWith runs through a list of key-value pairs [(k,v)] and adds them, one by one, to a new map.在这里, Map.fromListWith遍历键值对列表[(k,v)]并将它们一个一个地添加到新映射中。 As each pair is added, if the key isn't already in the map, the value (in your case, a singleton value like [1] or [2] ) is added under that key.添加每一对时,如果键不在地图中,则值(在您的情况下,像[1][2]这样的单例值)将添加到该键下。 If the key is already in the map, the new value is combined with the old value using the supplied function (++) (ie, as new_singleton_value ++ existing_list_of_values ).如果密钥已经在图中,新的值与使用提供的功能的旧值组合(++)即,作为, new_singleton_value ++ existing_list_of_values )。 This has the effect of creating a list of values in reverse order from the input list, so that's why I pre-processed the input list with reverse .这具有从输入列表以相反顺序创建值列表的效果,因此这就是我使用reverse预处理输入列表的原因。 (If the order doesn't matter, you should drop it.) (如果顺序无关紧要,您应该放弃它。)

A more common variant of this problem is writing a function that takes a list of pairs:这个问题的一个更常见的变体是编写一个函数,它接受一个对列表:

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

where the values aren't already lists.其中值尚未列出。 The solution is the same.解决方法是一样的。 You just pre-process the list with map (\\(k,v) -> (k,[v]) . This solution is covered in the other question mentioned in the comments.您只需使用map (\\(k,v) -> (k,[v])对列表进行预处理。评论中提到的另一个问题涵盖了此解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM