Scala:简单迭代最有效的集合

4
通常我会按需生成一个集合,以减少实例数据的大小。消费者在进行迭代之前只需要一次遍历集合,然后就被垃圾回收了。消费者不关心集合的顺序,不需要对其进行排序,当然也不需要对其进行变异或任何元素。在Scala中,最有效的类型安全集合是什么? - 是Array吗?
后续编辑:我想到有很多情况下都可以使用Set。在可能的情况下使用Set是好的还是只有在真正需要集合功能时才使用它们?

为什么不测量一下呢?我会期望,如果你不只是迭代它们来找到结尾 - 也许获取集合大小,但对每个对象进行一些真正的工作,那么花费在每个对象上的时间将远远超过按数量迭代的时间。 - user unknown
2
@userunknown 针对集合遍历的基准测试可以在以下链接中找到:http://paradigmatic.streum.org/2012/02/benchmarking-scala-list-traversal-idioms/ 和 http://codedependents.com/2012/04/30/benchmarking-more-seq-traversal-idioms-in-scala/。 - paradigmatic
2个回答

9

在所有的集合数据结构中,数组是拥有最少额外开销的,前提是你预先知道它们的大小。

如果你事先不知道大小,我仍然会选择 ArrayBuffer*。当底层数组用尽空间时,所使用的算法是最有效率的。

不要*使用(链接)ListStream,因为这些类涉及到每个元素一次堆分配。现代JVM垃圾收集器很好,但并非免费运行。

*:但是请看问题下@user unknown的评论,了解一些微基准测试的链接。目前的ArrayBuffer实现可能是次优的。

此外,请注意.view。通常您不需要实际存储中间结果。而是可以使用.map.filter等操作来构建对集合的“描述”。这些操作(映射、过滤等)只会在迭代集合时执行,通常在O(1)的空间内完成。缺点是,每次查询这些视图都将重新计算。(虽然这可能仍然比使用简单的过滤和庞大的基础集合更有效)

此外,请特别注意在可变数据结构上的视图。视图不捕获底层数据结构的状态。当它发生变化时,视图也会随之更改。然而,对于不可变数据结构的视图行为非常友好。最后,视图显然包含对底层数据结构的引用,这意味着只要您的程序持有该视图,它就不会被垃圾回收。

(已更新) Vectors 在存储效率和灵活性之间似乎取得了良好的平衡,特别是对于大序列而言。


你是否意识到在使用视图时需要注意的其他问题(性能或其他方面)? - sourcedelica

3

你需要存储元素吗?不能在需要的时候计算它们吗?如果你可以在需要的时候计算值而不是储存它们,你可以创建一个Traversable或者Iterable,几乎不用花费任何内存就可以完成工作(对于Traversable除了类本身外没有任何内存花费)。


在我所考虑的特定情况下,不需要。因此,在集合实际上未被实例化的情况下,Traversable或Iterable似乎是一个不错的选择。 - Rich Oliver

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