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