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