在 Erlang 中生成没有堆栈的幂集
注意:这是我之前关于幂集的问题的续集。
对于我之前的 关于生成集合的幂集而无需保留堆栈的问题:
class Array
def powerset
return to_enum(:powerset) unless block_given?
1.upto(self.size) do |n|
self.combination(n).each{|i| yield i}
end
end
end
# demo
['a', 'b', 'c'].powerset{|item| p item} # items are generated one at a time
ps = [1, 2, 3, 4].powerset # no block, so you'll get an enumerator
10.times.map{ ps.next } # 10.times without a block is also an enumerator
它可以完成这项工作并且效果很好。
但是,我想尝试在 Erlang 中重写相同的解决方案,因为对于 {|item| p item}
块我已经用 Erlang 编写了很大一部分工作代码(它对每个生成的子集做了一些事情)。
虽然我对 Erlang 有一些经验(我读过所有 2 本书:)),但我对 感到非常困惑示例以及sepp2k善意地给我回答了我之前关于幂集的问题的评论。我不理解示例的最后一行 - 我唯一知道的是这是一个列表理解。我不明白如何修改它以便能够对每个生成的子集执行某些操作(然后将其扔掉并继续处理下一个子集)。
如何在 Erlang 中重写这个 Ruby 迭代幂集生成?或者也许提供的 Erlang 示例已经几乎满足需要了?
Note: This is a sequel to my previous question about powersets.
I have got a nice Ruby solution to my previous question about generating a powerset of a set without a need to keep a stack:
class Array
def powerset
return to_enum(:powerset) unless block_given?
1.upto(self.size) do |n|
self.combination(n).each{|i| yield i}
end
end
end
# demo
['a', 'b', 'c'].powerset{|item| p item} # items are generated one at a time
ps = [1, 2, 3, 4].powerset # no block, so you'll get an enumerator
10.times.map{ ps.next } # 10.times without a block is also an enumerator
It does the job and works nice.
However, I would like to try to rewrite the same solution in Erlang, because for the {|item| p item}
block I have a big portion of working code already written in Erlang (it does some stuff with each generated subset).
Although I have some experience with Erlang (I have read all 2 books :)), I am pretty confused with the example and the comments that sepp2k kindly gave me to my previous question about powersets. I do not understand the last line of the example - the only thing that I know is that is is a list comprehension. I do not understand how I can modify it to be able to do something with each generated subset (then throw it out and continue with the next subset).
How can I rewrite this Ruby iterative powerset generation in Erlang? Or maybe the provided Erlang example already almost suits the need?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
所有给定的 示例 都有 O(2^N) 内存复杂度,因为它们返回整个结果(第一个例子)。最后两个示例使用常规递归,以便堆栈提升。下面的代码是示例的修改和编译,将执行您想要的操作:
在上面的代码片段中,使用了尾递归,该递归由 Erlang 编译器优化并在幕后转换为简单迭代。仅当递归调用是函数执行流程中的最后一个调用时,才可以通过这种方式优化递归。另请注意,每个生成的子集都可以用来代替注释,并且此后它将被遗忘(垃圾收集)。由于堆栈和堆都不会增长,但您还必须一个又一个地对子集执行操作,因为没有包含所有子集的最终结果。
我的代码对类似变量使用相同的名称(如示例中所示),以便更轻松地比较它们。我确信它可以针对性能进行改进,但我只想展示这个想法。
All the given examples have O(2^N) memory complexity, because they return whole result (the first example). Two last examples use regular recursion so that stack raises. Below code which is modification and compilation of the examples will do what you want:
In the above snippet tail recursion is used which is optimized by Erlang compiler and converted to simple iteration under the covers. Recursion may be optimized this way only if recursive call is the last one within function execution flow. Note also that each generated Subset may be used in place of the comment and it will be forgotten (garbage collected) just after that. Thanks to that neither stack nor heap won't grow, but you also have to perform operation on subsets one after another as there's no final result containing all of them.
My code uses same names for analogous variables like in the examples to make it easier to compare both of them. I'm sure it could be refined for performance, but I only want to show the idea.