【问题标题】:Sum all elements with same snd of a list Haskell对列表 Haskell 中具有相同 snd 的所有元素求和
【发布时间】:2013-08-18 22:10:58
【问题描述】:

我正在尝试在 Haskell 中做一个多项式计算器,但在乘法方面遇到了一些问题。多项式作为系数列表引入,其中第一项对应于 x^0,第二项对应于 x^1,依此类推。

对于乘法,我有一个元组列表,它们在第一个元素上表示它们所属的系数,在第二个元素上,它们显示相应的系数:

[(0,0),(0,-1),(0,-2),(0,-3),(0,-4),(0,1),(1,0),(2,-1),(3,-2),(4,-3),(0,2),(2,1),(4,0)

(这样做是为了保持对每个相乘项及其所属系数的引用)

因为这是我进入函数式编程的第一步,所以我在制作列表时遇到了一些麻烦,其中第一个元素是上面显示的列表中元组中所有第二个元素的总和,其中 0 作为第一个元素,第二项应该是上面显示的列表中元组中所有第二个元素的总和,其中 1 作为它的第一个元素,依此类推。

我尝试使用第一个答案here 中指出的 Data.Sequence 更新,但它似乎没有“更新”已经创建的 Data.Sequence,它每次都会返回一个新的。

有没有办法根据索引创建列表并更新其内容?我试图弄清楚如何递归地解决这个问题,但我不知道如何去做,所以任何帮助将不胜感激。

【问题讨论】:

  • 欢迎来到 Haskell。这个世界上的事情是简单的,不变的。因此,您无需每次更新而是创建一个新的不可变结构。
  • 我真的需要习惯它,因为我来自 Java、Python、C 等,这就像一个全新的视野。我一直在尝试列表理解,但找不到方法。
  • 学习 Haskell 的第一步是放下对效率和副本的顾虑。稍后,当您了解发生了什么时,您可以再次考虑效率问题。

标签: list haskell recursion


【解决方案1】:

这是解决方案,

import Data.List
import Data.Function

combine :: [(Int,Int)] -> [Int]
combine = map (sum . map snd) . groupBy ((==) `on` fst) . sort 

从右到左阅读函数以了解它在做什么。

这里是分解成更小的部分来理解它

*Main> sort [(0,0),(0,-1),(0,-2),(0,-3),(0,-4),(0,1),(1,0),(2,-1),(3,-2),(4,-3),(0,2),(2,1),(4,0)]
[(0,-4),(0,-3),(0,-2),(0,-1),(0,0),(0,1),(0,2),(1,0),(2,-1),(2,1),(3,-2),(4,-3),(4,0)]

这会对列表进行排序,因此具有相同第一个元素的所有对都在一起。在此之后,您还可以使用fold

*Main> groupBy ((==) `on` fst) . sort $ [(0,0),(0,-1),(0,-2),(0,-3),(0,-4),(0,1),(1,0),(2,-1),(3,-2),(4,-3),(0,2),(2,1),(4,0)]
[[(0,-4),(0,-3),(0,-2),(0,-1),(0,0),(0,1),(0,2)],[(1,0)],[(2,-1),(2,1)],[(3,-2)],[(4,-3),(4,0)]]

这将所有具有相同第一个元素的对组合在一起。

*Main> combine [(0,0),(0,-1),(0,-2),(0,-3),(0,-4),(0,1),(1,0),(2,-1),(3,-2),(4,-3),(0,2),(2,1),(4,0)]
[-7,0,0,-2,-3]

现在我们只需要计算列表列表中第二个元素的总和。

【讨论】:

  • 正是我想要的!感谢您的帮助,我必须习惯每次都建立一个新结构。
  • 我花了很长时间才回答,因为我试图理解代码,我想我必须理解它,但你的解释让它变得更好。再次感谢您!
  • @Jose_Sunstrider 它不像运行时系统实际上每次都构建一个新结构。由于不可变性,大部分东西都是共享的。编译器也有机会将上述操作融合到一个紧密的循环中,从而甚至不创建中间结构。
猜你喜欢
  • 1970-01-01
  • 2020-06-25
  • 1970-01-01
  • 2018-06-15
  • 2020-09-28
  • 1970-01-01
  • 1970-01-01
  • 2020-10-25
  • 1970-01-01
相关资源
最近更新 更多