更有效地压平和压缩阵列

时间:2015-12-21 16:53:31

标签: ruby

在很多情况下,我们需要对flattencompact等数组执行两项或更多操作。

some_array.flatten.compact

我担心的是它会循环遍历数组两次。有更有效的方法吗?

3 个答案:

答案 0 :(得分:5)

我实际上认为这是一个很好的问题。但首先,为什么大家都不太关心这个?以下是flattenflatten.compact的效果比较:

flatten performance

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)}