流vs视图vs迭代器


136

Scala中的Streams,Views(SeqView)和Iterators有什么区别?这是我的理解:

  • 它们都是惰性列表。
  • 流缓存值。
  • 迭代器只能使用一次?您无法回到开始并再次评估值?
  • 视图的值不会被缓存,但是您可以一次又一次地求值吗?

因此,如果我想节省堆空间,是否应该使用迭代器(如果我不再遍历列表)或视图?谢谢。


7
我之前已经回答过,但是如何找到呢?叹息...
Daniel C. Sobral'3

Answers:


182

首先,它们都是非严格的。这具有与功能有关的特定数学含义,但是,基本上,这意味着它们是按需计算的,而不是预先计算的。

Stream确实是一个懒惰列表。实际上,在Scala中,a Stream是,Listtailis是a lazy val。一旦计算出,值将保持计算状态并被重用。或者,正如您所说,这些值将被缓存。

An Iterator只能使用一次,因为它是指向 集合的遍历指针,而不是集合本身。在Scala中使其特别与众不同的是,您可以应用诸如map和的转换,filter而只是获得一个新的Iterator转换,该转换仅在您请求下一个元素时才应用这些转换。

Scala过去提供了可以重置的迭代器,但是很难以一般的方式来支持,并且他们没有制作2.8.0版本。

视图应像数据库视图一样进行查看。这是一系列转换,一个转换应用于一个集合以产生一个“虚拟”集合。如您所说,每次需要从中获取元素时,所有转换都将重新应用。

无论Iterator和观点具有优良的存储特性。Stream很好,但是在Scala中,它的主要好处是可以编写无限序列(尤其是递归定义的序列)。一个避免保持所有的Stream记忆,不过,通过确保你不饲养它的参考head(例如,通过使用def替代val来定义Stream)。

由于视图所带来的损失,通常应force在应用转换后将其视为视图,如果与视图的总大小相比,预计只有很少的元素被获取,则应将其保留为视图。


10
Iterator探测无限也很方便,并且在可能的情况下,我通常更喜欢它们而不是流。流中的真正好处是可以缓存先前访问的值,这在尝试实现像fibonacci序列之类的东西时是一个很大的福音,该序列是根据先前的值定义的。
凯文·赖特

5
斐波那契并不是一个完美的例子,因为它只需要前两个值,而保持整个数据流是浪费的。Ackermann函数可能是典型的例子。
尔根·斯特罗贝尔

4
@JürgenStrobelAckermann将导致糟糕的性能,因为流的索引访问为O(n)。但我同意斐波那契。
Daniel C. Sobral 2012年

9
啊对。对于任何缓存方法而言,Stream都不是一个好的选择。
尔根·斯特罗贝尔

7
这个答案非常清楚,它应该是文档的一部分...哦,实际上是!感谢Daniel docs.scala-lang.org/tutorials/FAQ/stream-view-iterator.html
Svend
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.