Ich habe gerade gelesen, dass die Ausführungszeit der Anfügungsoperation für ein List
(: +) linear mit der Größe des wächst List
.
Das Anhängen an a List
scheint eine ziemlich häufige Operation zu sein. Warum sollte die idiomatische Vorgehensweise darin bestehen, die Komponenten voranzustellen und dann die Liste umzukehren? Es kann auch kein Designfehler sein, da die Implementierung jederzeit geändert werden kann.
Aus meiner Sicht sollte sowohl das Voranstellen als auch das Anhängen O (1) sein.
Gibt es einen berechtigten Grund dafür?
List[T]
Es wird davon ausgegangen, dass Sie es so verwenden, wie Sie es in einer reinen funktionalen Sprache tun würden. In der Regel wird vom Kopf aus mit Dekonstruktion und Präfixen gearbeitet.Antworten:
Ich werde meinen Kommentar etwas erweitern. Die
List[T]
Datenstruktur vonscala.collection.immutable
ist so optimiert, dass sie so funktioniert, wie eine unveränderliche Liste in einer rein funktionalen Programmiersprache. Es hat sehr schnelle Vorlaufzeiten und es wird davon ausgegangen, dass Sie für fast alle Ihre Zugriffe am Kopf arbeiten werden.Unveränderliche Listen haben sehr schnelle Vorlaufzeiten, da sie ihre verknüpften Listen als eine Reihe von "Cons-Zellen" modellieren. Die Zelle definiert einen einzelnen Wert und einen Zeiger auf die nächste Zelle (klassischer einfach verknüpfter Listenstil):
Wenn Sie einer Liste voranstellen, erstellen Sie eigentlich nur eine einzelne neue Zelle, auf die der Rest der vorhandenen Liste verweist:
Da die Liste unveränderlich ist, können Sie dies ohne Kopieren tun . Es besteht keine Gefahr, dass sich die alte Liste ändert und alle Werte in Ihrer neuen Liste ungültig werden. Als Kompromiss verlieren Sie jedoch die Möglichkeit, einen veränderlichen Zeiger auf das Ende Ihrer Liste zu setzen.
Dies eignet sich sehr gut für die rekursive Bearbeitung von Listen. Angenommen, Sie haben Ihre eigene Version von
filter
:Dies ist eine rekursive Funktion, die ausschließlich vom Anfang der Liste aus funktioniert und den Pattern Matching über den :: Extractor nutzt. In Sprachen wie Haskell sieht man so viel.
Wenn Sie wirklich schnelle Anhänge wünschen, bietet Scala eine Vielzahl von veränderlichen und unveränderlichen Datenstrukturen zur Auswahl. Auf der veränderlichen Seite könnten Sie nachsehen
ListBuffer
. Alternativ hatVector
abscala.collection.immutable
eine schnelle Append-Zeit.quelle
else
eine Endlosschleife? Ich denke, es sollte so etwas seinx::deleteIf(xs)(f)
.head
undtail
Zugang mit dieser Art von Liste ist sehr schnell - schneller als jede Hash-basierte Karte oder Array - es ist eine ausgezeichnete Art für rekursive Funktionen. Dies ist einer der Gründe, warum Listen in den meisten funktionalen Sprachen (z. B. Haskell oder Scheme) ein zentraler Typ sindList
s und das Anhängen / Voranstellen haben).