【问题标题】:How to make fold perform multiple folds based on a category如何使折叠基于类别执行多次折叠
【发布时间】:2012-08-20 13:25:53
【问题描述】:

我可以将什么运算符传递给允许我在元组列表中对按元组项 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 的练习。我是新手。

我没有积分可以得到积分吗? :)

【问题讨论】:

  • 你有没有尝试过?
  • 折叠有点像函数式编程的“goto”:对某些事情很有用,但主要是作为更高层次的东西的垫脚石(比如groupBymap)。
  • @dbaupp:不。我看不出如何编写折叠运算符来执行子折叠。
  • @DanielWagner:谢谢,这个建议很好地支持了 shang 的回答。

标签: haskell fold


【解决方案1】:

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

实现您给出的示例的最简单方法是使用来自Data.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)]

【讨论】:

  • 好的,很漂亮。看到那里需要进行分组操作,我松了一口气,因为这是我的直觉告诉我的;但是我确信这是我对问题的爬虫命令式分析,我需要知道你的 Haskeller 是如何做到的。我现在想为多个键修改它,但我想我知道如何用你在这里给我的东西来做到这一点。谢谢!
【解决方案2】:

无意义的乐趣:

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

sumGroups = map (fst . head &&& sum . map snd) . groupBy ((==) `on` fst) 

【讨论】:

【解决方案3】:

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

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

【讨论】:

  • 乐高套件形式的答案;我会接受,因为它给了我一些研究关键词;谢谢你。我会说第一个转换让我感到困惑,因为我知道从那里将折叠映射到转换后的列表就是我所需要的。但是,groupBy 看起来很有趣。
猜你喜欢
  • 2013-01-16
  • 1970-01-01
  • 2019-03-02
  • 1970-01-01
  • 1970-01-01
  • 2020-08-29
  • 2017-01-05
  • 2022-11-02
  • 2015-06-26
相关资源
最近更新 更多