流 vs 视图 vs 迭代器

139

Streams,Views(SeqView)和Iterators在Scala中有哪些差异? 这是我的理解:

  • 它们都是惰性列表。
  • Streams缓存值。
  • 迭代器只能使用一次? 不能回到开头重新计算值?
  • View的值不被缓存,但可以多次评估?

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


2
请将以下相关编程内容从英语翻译为中文。 仅返回翻译文本:https://dev59.com/BW445IYBdhLWcg3wkLJG -------------- https://dev59.com/RnA75IYBdhLWcg3wUHSQ - Gene T
1个回答

184

首先,它们都是非严格的。这在函数相关的特定数学含义上有所体现,但基本上意味着它们是按需计算而不是提前计算。

Stream确实是一个延迟列表。事实上,在Scala中,Stream是一个List,其tail是一个lazy val。一旦计算完成,值就会保留并被重复使用。或者说,这些值被缓存了。

Iterator只能使用一次,因为它是指向集合的遍历指针,而不是集合本身。在Scala中,它的特殊之处在于您可以应用转换(例如mapfilter)并仅获取新的Iterator,该新的Iterator只会在请求下一个元素时应用这些转换。

Scala以前提供过可重置的迭代器,但这很难以一般方式支持,因此它们没有包含在版本2.8.0中。

视图类似于数据库视图,意为将一系列变换应用于集合以生成“虚拟”集合。正如您所说,每次需要从中获取元素时,所有变换都会被重新应用。

迭代器和视图都具有出色的内存特性。Stream很好用,但在Scala中,它的主要优点是编写无限序列(尤其是递归定义的序列)。不过,通过确保您不保留对其head的引用(例如,通过使用def而不是val来定义Stream),您可以避免将整个Stream保存在内存中。

由于视图所带来的惩罚,通常应在应用转换后force它,或者如果只需要从视图中提取少量元素,则应将其保留为视图,相较于视图的总大小。


11
Iterator 对于探索无限长度的数据也非常方便,通常情况下我更喜欢使用它们而不是 Stream。在 Stream 中的真正好处在于先前访问过的值被缓存,这对于实现诸如斐波那契数列之类需要使用以前的值来定义的算法非常有用。 - Kevin Wright
6
斐波那契数列并不是一个完美的例子,因为它只需要保留前两个值,而保留整个序列会浪费空间。阿克曼函数可能是一个经典的例子。 - Jürgen Strobel
5
@JürgenStrobel Ackermann的使用会导致性能较差,因为流的索引访问是O(n)。但我同意斐波那契方面的观点。 - Daniel C. Sobral
10
好的,这让Stream成为任何缓存方法的不良选择。 - Jürgen Strobel
8
这个答案非常清晰,它应该成为文档的一部分......哦,实际上已经是了!感谢Daniel。http://docs.scala-lang.org/tutorials/FAQ/stream-view-iterator.html - Svend
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接