Scala的toList函数似乎很慢

时间:2015-02-06 20:46:27

标签: scala

我的印象是在不可变的Seq上调用seq.toList()会产生一个新的列表,它从第一个列表中共享结构状态。我们发现这可能非常慢,我不知道为什么。它只是 共享结构状态,对吗?我不明白为什么当它知道它们永远不会改变时,它会为所有元素制作n次副本。

2 个答案:

答案 0 :(得分:6)

Scala中的List是一种特殊的数据结构:::的每个实例都包含一个值,后面跟着Nil

如果您toList List,则需要O(1)次。如果您在其他任何内容上toList ,则必须将其转换为List,其中涉及O(n)对象分配(所有::个实例)。

所以你必须问你是否想要一个scala.collection.immutable.List。这是toList给你的东西。

答案 1 :(得分:1)

对特定数据结构的特定操作可以共享结构状态。

使用Scala中的List数据结构,我的理解是每个元素都指向下一个元素,从头部开始到尾部,所以是单链表。

从结构状态共享的角度来看,从内部数据结构的角度考虑对此的限制。将元素添加到List(X)的头部有效地创建了一个新列表(X'),其中新元素作为X'的头部。和旧列表(X)作为尾部。对于此特定操作,可以完全共享内部状态。

上面的相同操作可用于创建新的List(X'),新元素作为X'的头部。并且X中的任何元素作为尾部,只要您接受尾部将是您从X中选择的元素,以及它已经具有的所有其他元素的数据结构。

当您从逻辑上考虑它时,每个数据结构都有一个内部结构,允许使用简单的共享内部结构执行某些操作,并且其他操作需要更多侵入性和昂贵的计算。

从我的角度来看,关键在于理解内部数据结构本身对操作的约束。

例如,在双向链表数据结构上考虑上述相同的操作,您将看到存在完全不同的限制。

就个人而言,我发现对内部结构的理解有助于理解特定操作的后果。

在对任意序列进行toList操作的情况下,不知道任意序列内部数据结构,因此必须假设为O(n)。 List.toList具有明显的性能优势,已经是列表。