我无法在合理的时间内获取 Enumerator
实例的无限序列的一部分。我首先尝试了 drop
和 take
链,但由于 drop
试图返回无限的 Array
,它永远挂起。接下来,我调换了这些方法的顺序,但我仍然需要等待大约十分钟才能在十百万次样本后获得 100 个值:
print exbioseq.drop(10**7).take(100)
有什么办法可以更快地获得切片吗?
最佳答案
安Enumerator
是非常通用的接口(interface),它只对它正在遍历的“集合”做出非常简单的假设。特别是,它实际上只支持两种操作:获取当前元素和迭代到下一个元素。
给定这两个操作,如果你想得到第 1000 万个元素,你只能做一件事:迭代 1000 万次。这需要时间。
不存在“切片”Enumerator
这样的事情.一个Enumerator
列举。就是这样。
现在,正如您发现的那样,存在另一个问题:Ruby 的集合操作不是类型保留的。不管你叫什么类型的收藏map
或 select
或 take
或者其他什么,它总是返回相同的类型:一个完全实现的、具体的、严格的 Array
.这就是大多数语言中的大多数集合框架的工作方式,例如在 .NET 中,所有集合操作都返回 IEnumerable
.这是因为大多数这些方法在 Enumerable
中只有一个通用实现。混入。
Smalltalk 是个异常(exception),但还有另一个问题:每个集合类型的集合操作都是重复的。每种集合类型都有自己的 collect:
的几乎完全相同的实际复制和粘贴实现。 , select:
等等。这种代码重复很难维护,并且给任何想要将他们自己的集合集成到框架中的人带来很大的负担。在 Ruby 中,这很简单:实现 each
, 混合 Enumerable
大功告成。
注意:从 Ruby 1.9 开始,实际上有 一些 的重复:Hash
实现自己的 select
版本它实际上返回一个 Hash
而不是 Array
.所以,现在,不仅存在代码重复,而且接口(interface)中存在不对称:select
的所有实现。返回 Array
除了 Hash
中的那个.
Scala 2.8 集合框架是有史以来第一次有人想出如何在不重复代码的情况下提供类型保留集合操作。但是 Ruby 的集合框架是在 Scala 2.8 之前 15 年设计的,因此它无法利用这些知识。
在 Ruby 2.0 中,有惰性 Enumerator
s,所有收集操作返回另一个惰性 Enumerator
.但这对你没有帮助:唯一的区别是懒惰的 Enumerator
将延迟 1000 万次迭代,直到您实际 print
值(value)。它仍然必须执行那 1000 万次迭代,因为除此之外别无他法。
如果你想切片,你需要一个可切片的数据结构,比如Array
.
关于ruby - 有效地获取枚举器的切片,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14978084/