我一直在尝试解决这个问题,但就是想不通。所以,我有一个包含元组的列表,例如:
[("Mary", 10), ("John", 45), ("Bradley", 30), ("Mary", 15), ("John", 10)]
我想要得到的是一个包含元组的列表,如果名称相同,则应添加这些元组的编号,如果不相同,则该元组也必须是最终列表的一部分,例如:
[("Mary",25), ("John", 55), ("Bradley", 30)]
我不知道我是否解释得很好,但我想您可能会通过示例理解。
我已经试过了,但它不起作用:
test ((a,b):[]) = [(a,b)]
test ((a,b):(c,d):xs) | a == c = (a,b+d):test((a,b):xs)
| otherwise = (c,d):test((a,b):xs)
最佳答案
用列表做这类事情总是很尴尬,因为它们的顺序性质——它们并不真正适合“查找匹配项”或“通过组合列表元素的特定组合计算新列表”之类的操作或其他本质上不连续的事物。
如果您退后一步,您真正想要做的是,对于列表中的每个不同的 String
,找到与其关联的所有数字并将它们相加。这听起来更适合键值样式的数据结构,在 Haskell 中最标准的是 is found in Data.Map
,它为您提供任何值类型和任何有序键类型(即 Ord
的实例)的键值映射。
因此,要从您的列表构建一个 Map
,您可以使用 Data.Map
中的 fromList
函数... ,期望以键值元组列表的形式输入。所以你可以这样做......
import qualified Data.Map as M
nameMap = M.fromList [("Mary", 10), ("John", 45), ("Bradley", 30), ("Mary", 15), ("John", 10)]
...但这并不好,因为直接插入它们会覆盖数字而不是添加它们。你可以use M.fromListWith
to specify how to combine values当插入重复的键时——在一般情况下,通常使用它来为每个键或类似的东西构建一个值列表。
但在您的情况下,我们可以直接跳到所需的结果:
nameMap = M.fromListWith (+) [("Mary", 10), ("John", 45), ("Bradley", 30), ("Mary", 15), ("John", 10)]
如果找到一个新名称,这将直接插入,否则它将在副本上添加值(数字)。如果愿意,您可以使用 M.toList
将其转回元组列表:
namesList = M.toList $ M.fromListWith (+) [("Mary", 10), ("John", 45), ("Bradley", 30), ("Mary", 15), ("John", 10)]
这给了我们 [("Bradley",30),("John",55),("Mary",25)]
的最终结果。
但是如果您想对姓名/号码集合做更多的事情,在完成之前将其保留为 Map
可能更有意义。
关于haskell - 使用元组列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14095496/