4

我可以将什么运算符传递给允许我在元组列表中对按元组项 1 分组的元组项 2 进行求和的折叠变体之一?

所以,假设我有清单:

[ ('A', 1) , ('A', 3) , ('B', 4 ) , ('C', 10) , ('C', 1) ]

我想制作清单:

[ ('A', 4) , ('B', 4) , ('C', 11) ]

你可以看到它是一个 Haskell 化的表,所以这里的表的实际表示并不重要;这是获取输入数据并生成我感兴趣的输出的方法。我是 Haskell 新手,具有 C/C++/C# 的背景。我已经完成了足够多的教程来识别此处折叠的应用,但无法弄清楚似乎需要的子折叠。

编辑:如果这对其他人有帮助,这是我使用 group、foldl1 和 map 的解决方案,灵感来自 ingo 的回复:

import qualified Data.List as List

mygroup :: [ (Char,Int) ] -> [ [(Char,Int)] ]
mygroup = List.groupBy (\x y -> fst x == fst y) 

myfold :: [(Char,Int)] -> (Char,Int)
myfold = foldl1 (\x y -> (fst x, snd x + snd y))

mysum :: [(Char,Int)] -> [(Char,Int)]
mysum = map myfold . mygroup

运行时:

*ListSum> mysum [ ('A',1) , ('A',2) , ('B',3) , ('C',4) , ('C',5) ]
[('A',3),('B',3),('C',9)]

mygroup通过提供等价运算符展示了如何创建组。它表示如果两个成员的第一个元组项相同,则两个成员在同一个组中。

myfold展示了如何对两个元组求和。它使用列表中的第一个元组作为折叠的初始状态,并根据每个元组的第二项之和组成一个结果元组。

mysum使用 map 组合这两个函数。

我可能会花更多的时间来看看我是否可以打破对数据模式的依赖,目前是[(Char,Int)]。我认为这意味着提供 groupBy 运算符和 fold 运算符,并且可能只是组合 groupBy、foldl1 和 map 的练习。我是新来的。

我是否会因无积分而获得任何积分?:)

4

3 回答 3

4

您真正想要的是使用特定标准对项目进行分组,然后将这些组折叠起来。

实现您给出的示例的最简单方法是使用关联映射 fromData.Map对项目进行分组。

import qualified Data.Map as Map

sumGroups :: [(Char, Int)] -> [(Char, Int)]
sumGroups = Map.assocs . Map.fromListWith (+)

这使用该函数fromListWith来组合具有相同键的项目,并将生成的映射转换回带有assocs.

*Main> sumGroups [ ('A', 1) , ('A', 3) , ('B', 4 ) , ('C', 10) , ('C', 1) ]
[('A',4),('B',4),('C',11)]
于 2012-08-20T13:40:49.433 回答
3

无意义的乐趣:

import Data.List
import Data.Function
import Control.Arrow

sumGroups = map (fst . head &&& sum . map snd) . groupBy ((==) `on` fst) 
于 2012-08-20T21:34:58.303 回答
2

从概念上讲,您需要两个步骤:

transform [('A', 1) , ('A', 3) , ('B', 4 ) , ('C', 10) , ('C', 1)]
to [('A', [1,3,4]), ('C', [10, 1])]
and further to [('A', 8), ('C', 11)]

对您有帮助的函数:groupBy、using、fst、map、sum

于 2012-08-20T13:55:05.697 回答