Unterschied zwischen Array und Liste in Scala

141

In welchen Fällen sollte ich Array (Puffer) und Liste (Puffer) verwenden. Ich weiß nur, dass Arrays nicht variabel und Listen kovariant sind. Aber was ist mit der Leistung und einigen anderen Eigenschaften?

Jeriho
quelle

Antworten:

155

Unveränderliche Strukturen

Die Scala Listist eine unveränderliche rekursive Datenstruktur, die in Scala eine so grundlegende Struktur darstellt, dass Sie sie (wahrscheinlich) viel häufiger verwenden sollten als eine Array(die tatsächlich veränderlich ist - das unveränderliche Analogon von Arrayist IndexedSeq).

Wenn Sie von einem Java - Hintergrund kommen, dann ist die offensichtliche Parallele ist zu verwenden , wenn LinkedListüber ArrayList. Ersteres wird im Allgemeinen für Listen verwendet, die immer nur durchlaufen werden (und deren Größe im Voraus nicht bekannt ist), während letzteres für Listen verwendet werden sollte, die entweder eine bekannte Größe (oder maximale Größe) haben oder für die ein schneller Direktzugriff wichtig ist.

Mutable Strukturen

ListBufferbietet eine zeitkonstante Konvertierung zu a, Listwas allein Grund zur Verwendung ist, ListBufferwenn eine solche spätere Konvertierung erforderlich ist.

Eine Scala Arraysollte in der JVM von einem Java-Array implementiert werden, und daher Array[Int]kann eine Scala (als int[]) viel leistungsfähiger sein als eine List[Int](die ihren Inhalt verpackt, es sei denn, Sie verwenden die neuesten Versionen von Scala mit der neuen @specializedFunktion). .

Ich denke jedoch, dass die Verwendung von Arrays in Scala auf ein Minimum beschränkt werden sollte, da Sie wirklich wissen müssen, was unter der Haube vor sich geht, um zu entscheiden, ob Ihr Array wirklich durch den erforderlichen primitiven Typ unterstützt wird oder möglicherweise als Wrapper-Typ verpackt sein.

oxbow_lakes
quelle
Siehe auch stackoverflow.com/questions/3213368/… und stackoverflow.com/questions/2481149/…. Die Definition von "gleich" für Arrays lautet, dass sie sich auf dasselbe Array beziehen
oluies
130

Zusätzlich zu den bereits veröffentlichten Antworten finden Sie hier einige Besonderheiten.

Während a Array[A]buchstäblich ein Java-Array ist, List[A]ist a eine unveränderliche Datenstruktur, die entweder Nil(die leere Liste) ist oder aus einem Paar besteht (A, List[A]).

Leistungsunterschiede

                          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)

Speicherunterschiede

                          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)

Wenn Sie also keinen schnellen Direktzugriff benötigen, keine Elemente zählen müssen oder aus irgendeinem Grund destruktive Aktualisierungen benötigen, Listist a besser als a Array.

Apocalisp
quelle
Müssen diese Os die Zeit berücksichtigen, um die Liste zu kopieren? Ich gehe davon aus, dass Sie den Test so durchführen, z list = list.drop(i). Oder tritt etwas Magie hinter der Haube auf?
2
Dies berücksichtigt bei Bedarf das Kopieren von Listen und Arrays. Beachten Sie, dass Dinge wie dropnie den Teil der Liste kopieren müssen, der nicht gelöscht wurde. ZB (x::xs).drop(1)ist genau xs, keine "Kopie" von xs.
Apocalisp
6
Diese Asymptotiker haben überhaupt nichts mit Scala zu tun. Die gleiche Datenstruktur in C ist bis zu konstanten Faktoren genauso schnell.
Apocalisp
1
@Apocalisp Haben Sie eine Referenz oder unter welchen Bedingungen haben Sie diese Informationen ermittelt?
Phil
1
@Phil Dies sind Asymptotika, keine Messungen. Sie gelten unter allen Bedingungen.
Apocalisp
18

Ein Array ist veränderbar, dh Sie können die Werte jedes Index ändern, während eine Liste (standardmäßig) unveränderlich ist. Dies bedeutet, dass bei jeder Änderung eine neue Liste erstellt wird. In den meisten Fällen ist es ein „funktional“ Stil der Arbeit mit unveränderlichen Datentypen und Sie sollten wahrscheinlich versuchen, eine Liste mit Konstrukten wie verwenden yield, foreach, matchund so weiter.

Bei Leistungsmerkmalen ist ein Array mit wahlfreiem Zugriff auf Elemente schneller, während eine Liste schneller ist, wenn neue Elemente vorangestellt (hinzugefügt) werden. Über sie zu iterieren ist vergleichbar.

leonm
quelle
@leonm - apols, ich dachte, das OP fragt ausschließlich nach den * Buffer-Klassen, mir ist klar, dass sie auch nach den "normalen" fragen!
oxbow_lakes
2
Das Anhängen an einen ArrayBuffer ist normalerweise schneller als das Voranstellen an eine Liste (oder das Hinzufügen eines Elements zu einem ListBuffer), da für Listen ein Wrapper-Objekt erstellt werden muss, während ArrayBuffer das Objekt lediglich (durchschnittlich etwa zweimal) in ein neues Array kopieren muss . Zwei Kopien sind normalerweise schneller als eine Objekterstellung, daher schlägt das ArrayBuffer-Anhängen normalerweise das Listenvoranstellen.
Rex Kerr
Array arbeitet viel schneller als Liste, wenn iterate overwegen Cache
Bin