在很多场合,我们需要像flatten
和compact
阵列上执行两个或两个以上不同的操作。扁平化和紧凑阵列更有效地
some_array.flatten.compact
我这里关注的是,它会循环阵列上两次。有没有更有效的方法来做到这一点?
在很多场合,我们需要像flatten
和compact
阵列上执行两个或两个以上不同的操作。扁平化和紧凑阵列更有效地
some_array.flatten.compact
我这里关注的是,它会循环阵列上两次。有没有更有效的方法来做到这一点?
我其实觉得这是一个很好的问题。但首先,为什么每个人都不太在意呢?下面是flatten
和flatten.compact
相比性能:
Here's the code I used to generate this chart, and one that includes memory.
希望现在你明白为什么大多数人会担心:这只是你在撰写flatten
添加另一常数因子用compact
,也许是有价值的,至少从理论上说:我们怎样才能剃除时间和空间这个中间结构的?再次,渐近地不是超级有价值的,但好奇想想。
据我所知,你不能利用的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一致。
因此源代码可以一直这样写这样会被允许额外的设置,如果一个块中传递工作。但是,如果没有,你就坚持与(小)的性能损失!
顺便说一句,如果你真的想要能够做到这一点,我写了一个C扩展,增加了一个新的函数'collapse':https://github.com/mooreniemi/array_collapse –
它是不一样的阵列上进行迭代两次。 flatten
通常会创建一个与原始结构完全不同的结构。因此,第一次和第二次迭代不会迭代相同的元素。所以,自然而然地,你不能那样做。
true,但它仅仅意味着第二次循环会变得更小,它仍然会更有效率地做到这一点一旦。 –
当然,你自己动手做。 –
是的,从自己的循环到使用C++而不是Ruby,有许多更有效的方法。问题是:你为什么在意?这实际上是一种瓶颈吗? – meagar
你可以手动循环或获得一个懒惰的枚举器(假设你想使用的所有方法都在'Enumerable'中)。 – ndn