Scala中数组和列表之间的区别


141

在什么情况下我应该使用Array(Buffer)和List(Buffer)。我知道的唯一一个区别是数组是不变的,而列表是协变的。但是性能和其他一些特征呢?

Answers:


155

不变结构

斯卡拉List是不可变的递归数据结构,它是Scala这样的基本结构,你应该(可能)使用它远远超过一个是Array(这实际上是可变的 -的不可变模拟ArrayIndexedSeq)。

如果您来自Java背景,那么显而易见的并行是何时使用LinkedListover ArrayList。前者通常用于仅遍历过的列表(其大小事先未知),而后者应用于具有已知大小(或最大大小)或快速随机访问很重要的列表。

可变结构

ListBuffer提供了对a的恒定时间转换,如果需要进行后期转换List,则仅使用ListBuffer该转换的理由。

一个scala Array应该通过Java数组在JVM上实现,因此Array[Int]可能比的性能更高(作为int[]List[Int](将装箱其内容,除非您使用的是具有新@specialized功能的最新版本的Scala ) 。

但是,我认为Array应尽量减少在Scala中使用s,因为感觉就像您真的需要知道幕后发生的事情一样,才能确定您的数组是否真正由所需的原始类型支持,或者被包装为包装类型。


另请参见stackoverflow.com/questions/3213368/…stackoverflow.com/questions/2481149/…Array 的“等于”的定义是它们指的是同一阵列
oluies 2010年

130

除了已经发布的答案之外,这里还有一些细节。

虽然Array[A]从字面上看是Java数组,但是a List[A]是一个不变的数据结构,该结构要么是Nil(空列表),要么是由pair组成(A, List[A])

性能差异

                          Array  List
Access the ith element    θ(1)   θ(i)
Delete the ith element    θ(n)   θ(i)
Insert an element at i    θ(n)   θ(i)
Reverse                   θ(n)   θ(n)
Concatenate (length m,n)  θ(n+m) θ(n)
Count the elements        θ(1)   θ(n)

记忆差异

                          Array  List
Get the first i elements  θ(i)   θ(i)
Drop the first i elements θ(n-i) θ(1)
Insert an element at i    θ(n)   θ(i)
Reverse                   θ(n)   θ(n)
Concatenate (length m,n)  θ(n+m) θ(n)

因此,除非您需要快速随机访问,需要对元素进行计数或出于某种原因需要破坏性更新,否则a List优于an Array


这些操作系统是否需要考虑复制列表的时间?我假设您正在像这样进行测试,例如:list = list.drop(i)。或者,引擎盖后面是否发生了某些魔术?

2
这在必要时考虑了复制列表和数组。注意,诸如drop从不需要复制列表中未被删除的部分之类的事情。例如(x::xs).drop(1),完全是xs,而不是的“副本” xs
Apocalisp

6
这些无症状与Scala无关。在C中,相同的数据结构将达到恒定因子的速度。
Apocalisp

1
@Apocalisp您是否有参考文献或在什么条件下确定此信息?
菲尔(Phil)

1
@Phil这些是无症状的,不是度量。它们在所有条件下都适用。
Apocalisp

18

数组是可变的,这意味着您可以更改每个索引的值,而列表(默认情况下)是不可变的,这意味着每次您进行修改时都会创建一个新列表。在大多数情况下,它是一个更“实用”的风格与不可改变的数据类型的工作,你或许应该尝试使用列表中包含结构yieldforeachmatch等等。

对于性能特征,使用数组随机访问元素会更快,而在添加(添加)新元素时,列表会更快。遍历它们是可比较的。


@leonm-apols,我以为OP仅在询问* Buffer类,我意识到他们也在询问“普通”类!
oxbow_lakes

2
通常,追加到ArrayBuffer比添加到List(或将元素添加到ListBuffer)要快得多,因为列表需要创建包装对象,而ArrayBuffer只需将对象(平均大约两次)复制到新数组即可。 。通常,两个副本比一个对象的创建速度快,因此ArrayBuffer追加通常比List优先。
雷克斯·克尔

iterate over由于高速缓存,数组的执行速度比列表快得多
Bin Bin
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.