在很多情况下,我们需要对flatten
和compact
等数组执行两项或更多操作。
some_array.flatten.compact
我担心的是它会循环遍历数组两次。有更有效的方法吗?
答案 0 :(得分:5)
我实际上认为这是一个很好的问题。但首先,为什么大家都不太关心这个?以下是flatten
和flatten.compact
的效果比较:
Here's the code I used to generate this chart, and one that includes memory.
希望现在你明白为什么大多数人都不会担心:当你用flatten
撰写compact
时,这只是你要添加的另一个常数因素,也许是&#39至少在理论上有价值地说:我们怎样才能减掉这个中间结构的时间和空间?再次,渐近不是超级有价值,但好奇想想。
据我所知,您无法通过flatten
来实现这一目标:
在查看来源之前,我希望flatten
可以采取这样的方式:
[[3, [3, 3, 3]], [3, [3, 3, 3]], [3, [3, 3, 3]], nil].flatten {|e| e unless e.nil? }
尽管没有骰子。我们将此作为回报:
[3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, nil]
这很奇怪,因为它基本上把这块作为无操作扔掉了。但是source是有意义的。 Ruby核心中使用的C方法flatten
没有被参数化以进行阻塞。
Ruby源代码中的过程对我来说有点奇怪(我不是C程序员)但它基本上做了深度优先搜索等操作。它使用一个堆栈,它将每个新的嵌套数组添加到它遇到的进程中。 (当没有剩下时它终止。)我没有正式计算,但它让我猜测复杂性与DFS相同。
因此,源代码可能已被编写,如果传入一个块,可以通过允许额外的设置来实现。但如果没有这个,你就会遇到(小)性能损失!
答案 1 :(得分:1)
它不会在同一个数组上迭代两次。 flatten
通常会创建一个与原始数组完全不同的数组。因此,第一次和第二次迭代不会迭代相同的元素。所以,很自然地说你无法做到这一点。
答案 2 :(得分:0)
如果数组是一层深,那么数组可以合并为一组。
require 'set'
s = Set.new
Ar.each{|a| s.merge(a)}