Scalaでの配列とリストの違い


142

どのような場合にArray(Buffer)とList(Buffer)を使用する必要があります。私が知っている唯一の違いは、配列は不変で、リストは共変であるということです。しかし、パフォーマンスと他のいくつかの特性はどうですか?

回答:


155

不変の構造

ScalaはListあなたが(おそらく)よりもはるかにそれを使用しなければならないことを、Scalaでは、このような基本構造である不変の再帰的なデータ構造であるArray(実際にある可変 - 不変アナログArrayですIndexedSeq)。

Javaのバックグラウンドを使用LinkedListしている場合、明らかな類似点は、いつover を使用するかArrayListです。前者は通常、トラバースされるだけの(かつ、サイズが事前にわからない)リストに使用されますが、後者は、既知のサイズ(または最大サイズ)または高速ランダムアクセスが重要なリストに使用する必要があります。

可変構造

ListBufferは、への定数時間変換を提供します。Listこれは、このListBufferような後の変換が必要な場合にのみ使用する理由です。

ScalaはArrayJava配列によってJVM上で実施されるべきであり、それゆえArray[Int]はるかにパフォーマンス(ようなものであってもよいint[])よりもList[Int](あなたが新しい持つスカラ座の非常に最新のバージョンを使用している場合を除き、その内容をボックスなる@specialized機能) 。

ただし、ArrayScala でのs の使用は最小限に抑える必要があると思います。なぜなら、配列が本当に必要なプリミティブ型によって裏付けられるかどうかを判断するには、内部で何が行われているのかを本当に知る必要があるからです。ラッパータイプとしてボックス化されます。


参照stackoverflow.com/questions/3213368/...をしてstackoverflow.com/questions/2481149/... 配列のための「対等」の定義は、彼らが同じ配列を参照していることである
oluies

130

既に投稿された回答に加えて、ここにいくつかの詳細があります。

しながら、Array[A]文字通りJava配列である、List[A]のいずれかである不変データ構造であるNil(空のリスト)又は対で構成され(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 ListArray


これらのOは、リストをコピーする時間を考慮する必要がありますか?私はあなたがこのようなテストをしていると思います、例えば:list = list.drop(i)。または、フードの背後で何らかの魔法が発生しますか?

2
これは、必要に応じてリストと配列のコピーを考慮に入れています。のようなものdropは、ドロップされなかったリストの部分を決してコピーする必要がないことに注意してください。たとえば、(x::xs).drop(1)は正確にxsであり、の「コピー」ではありませんxs
Apocalisp 2013年

6
これらの漸近性は、Scalaとは何の関係もありません。Cの同じデータ構造は、一定の因子まで正確に高速になります。
Apocalisp 2013年

1
@Apocalisp参考資料はありますか、またはどのような条件下でこの情報を決定しましたか?
Phil

1
@Philこれは漸近的なものであり、測定値ではありません。それらはすべての条件下で当てはまります。
Apocalisp 2016年

18

配列は変更可能です。つまり、各インデックスの値を変更できます。リスト(デフォルト)は不変です。つまり、変更を行うたびに新しいリストが作成されます。ほとんどの場合、それは不変のデータ型の仕事に多くの「機能的」なスタイルで、あなたはおそらくしようとするような構築物でリストを使用する必要がありyieldforeachmatchなど。

パフォーマンス特性については、要素へのランダムアクセスを使用すると配列が高速になりますが、新しい要素を先頭に追加(追加)するときはリストが高速になります。それらを繰り返すことは同等です。


@leonm-apols、私はOPが* Bufferクラスのみについて質問していると思いました、私は彼らが「通常の」クラスについても質問していることを理解しています!
oxbow_lakes 2010

2
ArrayBufferがオブジェクトを(平均で約2回)新しい配列にコピーするだけでよいのに対し、リストはラッパーオブジェクトの作成を必要とするため、通常、リストの先頭に追加する(またはListBufferに要素を追加する)よりもArrayBufferに追加する方が高速です。 。通常、2つのコピーは1つのオブジェクトの作成よりも高速であるため、ArrayBufferの追加は通常、リストの先頭に追加されます。
レックスカー

iterate overキャッシュのため、配列はリストよりもはるかに高速に実行されます
Bin
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.