使用元组列表

Rap*_*phm 2 haskell tuples

我一直试图解决这个问题,但我无法弄明白.所以,我有一个带有元组的列表,例如:

[("Mary", 10), ("John", 45), ("Bradley", 30), ("Mary", 15), ("John", 10)]
Run Code Online (Sandbox Code Playgroud)

我想得到的是一个带有元组的列表,如果名称相同,则应添加这些元组的数量,如果不是,那个元组也必须是最终列表的一部分,举例说明:

[("Mary",25), ("John", 55), ("Bradley", 30)]
Run Code Online (Sandbox Code Playgroud)

我不知道我是否真的很好地解释了自己,但我想你可能会理解这些例子.

我试过这个,但它不起作用:

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)
Run Code Online (Sandbox Code Playgroud)

C. *_*ann 8

对于列表来说,做这类事总是很尴尬,因为它们具有顺序性 - 它们并不真正适用于"查找匹配项"或"通过组合列表元素的特定组合来计算新列表"等操作.这本质上是非顺序的.

如果您退后一步,那么您真正想要做的是,对于String列表中的每个不同,找到与其关联的所有数字并将其添加.这听起来更适合于键值样式的数据结构,在Haskell 中找到Data.Map最标准的数据结构,它为任何值类型和任何有序键类型(即实例Ord)提供键值映射.

因此,Map要从列表中构建一个,您可以使用...中的fromList函数Data.Map,方便地,期望以键值元组列表的形式输入.所以你可以这样做......

import qualified Data.Map as M

nameMap = M.fromList [("Mary", 10), ("John", 45), ("Bradley", 30), ("Mary", 15), ("John", 10)]
Run Code Online (Sandbox Code Playgroud)

...但这并不好,因为直接插入它们会覆盖数字而不是添加它们.您可以使用它M.fromListWith来指定在插入重复键时如何组合值 - 在一般情况下,通常使用它来为每个键或类似事物构建值列表.

但在您的情况下,我们可以直接跳到所需的结果:

nameMap = M.fromListWith (+) [("Mary", 10), ("John", 45), ("Bradley", 30), ("Mary", 15), ("John", 10)]
Run Code Online (Sandbox Code Playgroud)

如果找到新名称,将直接插入,否则将在副本上添加值(数字).如果您愿意,可以使用M.toList以下命令将其重新转换为元组列表:

namesList = M.toList $ M.fromListWith (+) [("Mary", 10), ("John", 45), ("Bradley", 30), ("Mary", 15), ("John", 10)]
Run Code Online (Sandbox Code Playgroud)

这给了我们最终的结果[("Bradley",30),("John",55),("Mary",25)].

但是如果你想用名字/数字的集合做更多的事情,Map那么在你完成之前保持它可能更有意义.