【发布时间】:2016-02-25 06:10:51
【问题描述】:
我是函数式编程的新手,我正在尝试找出一个函数,它可以递归地生成一组列表的笛卡尔积的元素。
我正在寻找的功能与sequence 完全一样(如此处所述:Calculate n-ary Cartesian Product),只是我不想将整个内容表达为一个列表。
我目前正在使用sequence 并遇到此处描述的问题的变体:Summing a large list of numbers is too slow。
例如,sequence [[1,2,3],[1,2,3]] 产生 [[1,1],[1,2],[1,3],[2,1],[2,2],[2,3],[3,1],[3,2],[3,3]]。处理每个组合是完全可以接受的(即[1,2]等,作为一个列表,我只是想避免建立长的外部列表,而是在计算数据时递归处理数据。我将如何去做?
我目前正在做类似于这个快速 ghci 示例的事情:
> let stuff = sequence $ replicate 10 [0..9]
> let morestuff = map (sum . take 2 . reverse . sort) stuff
> sum morestuff
最后一个命令太慢了。
【问题讨论】:
-
“在计算数据时递归处理数据”到底是什么意思?这正是 Haskell 中惰性求值的工作原理。
-
最后一个命令将强制计算 each 组合(其中有 10^10 个) - 我认为你应该专注于你的算法而不是这里的评估细节首先
-
例如:对于每个组合,您只使用两个最大的数字并将它们相加 - 所以您不需要购物车。完全没有产品(您只需再次排序)......只需寻找一种以已经排序的方式生成它们的方法(并将总和乘以之后的排列数)......我认为这实际上更像是一个数学问题(这是一个欧拉项目吗?)我不想破坏太多,因为它可能是一些竞赛^^
-
顺便说一句:即使您不知道该怎么做,您也可以从优化
sum . take 2 .reverse . sort的东西开始 - 即使您只遍历列表一次并寻找两个最大的元素并求和起来,你会节省很多 -
尝试在每个
let之间强制列出列表,您会发现在所有阶段都花费了很多时间——懒惰只是意味着您只能在除非你早点强迫,否则结束。在 repl 处强制执行的一种方法是使用来自Control.DeepSeq的rnf。也就是说,您正在生成和汇总大约 10^10 个东西,也就是说 100 亿。因此,无论您如何编写代码,我都无法想象这会顺利进行。
标签: performance haskell functional-programming cartesian-product