用列表做这种事情总是很尴尬,因为它们的顺序性——它们并不适合像“查找匹配项”或“通过组合列表元素的特定组合来计算新列表”或其他事情这样的操作本质上是非连续的。
如果你退后一步,你真正想做的是,对于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)]
...但这不好,因为直接插入它们会覆盖数字而不是添加它们。您可以使用M.fromListWith
指定在插入重复键时如何组合值- 在一般情况下,通常使用它来为每个键或类似事物构建值列表。
但在您的情况下,我们可以直接跳到所需的结果:
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)]
。
但是,如果您想对名称/数字的集合做更多的事情,那么在完成之前将其保留为 a 可能更有意义Map
。