Stream vs Ansichten vs Iteratoren

136

Was sind die Unterschiede zwischen Streams, Ansichten (SeqView) und Iteratoren in Scala? Das ist mein Verständnis:

  • Sie sind alle faule Listen.
  • Streams speichern die Werte zwischen.
  • Iteratoren können nur einmal verwendet werden? Sie können nicht zum Anfang zurückkehren und den Wert erneut bewerten?
  • Die Werte von View werden nicht zwischengespeichert, aber Sie können sie immer wieder auswerten?

Wenn ich also Heap-Speicherplatz sparen möchte, sollte ich Iteratoren (wenn ich die Liste nicht erneut durchlaufen möchte) oder Ansichten verwenden? Vielen Dank.

JWC
quelle
7
Ich habe das schon einmal beantwortet, aber wie finde ich es? seufz ...
Daniel C. Sobral

Antworten:

182

Erstens sind sie alle nicht streng . Dies hat eine bestimmte mathematische Bedeutung in Bezug auf Funktionen, bedeutet jedoch im Grunde, dass sie bei Bedarf statt im Voraus berechnet werden.

Streamist in der Tat eine faule Liste. Tatsächlich ist in Scala a Streamein, Listdessen a tailist lazy val. Nach der Berechnung bleibt ein Wert berechnet und wird wiederverwendet. Oder, wie Sie sagen, die Werte werden zwischengespeichert.

Ein Iteratorkann nur einmal verwendet werden, da es sich um einen Durchlaufzeiger in eine Sammlung handelt und nicht um eine Sammlung an sich. Das Besondere an Scala ist die Tatsache, dass Sie Transformationen wie mapund anwenden können filterund einfach eine neue erhalten, Iteratordie diese Transformationen nur anwendet, wenn Sie nach dem nächsten Element fragen.

Scala stellte früher Iteratoren bereit, die zurückgesetzt werden konnten, aber das ist im Allgemeinen sehr schwer zu unterstützen, und sie haben Version 2.8.0 nicht erstellt.

Ansichten sollen ähnlich wie eine Datenbankansicht angezeigt werden. Es ist eine Reihe von Transformationen, die man auf eine Sammlung anwendet, um eine "virtuelle" Sammlung zu erzeugen. Wie Sie sagten, werden alle Transformationen jedes Mal neu angewendet, wenn Sie Elemente daraus abrufen müssen.

Beide Iteratorund Ansichten weisen hervorragende Speichereigenschaften auf. Streamist schön, aber in Scala besteht sein Hauptvorteil darin, unendliche Sequenzen zu schreiben (insbesondere Sequenzen, die rekursiv definiert sind). Sie können jedoch vermeiden, den gesamten StreamSpeicher zu behalten, indem Sie sicherstellen, dass Sie keinen Verweis darauf behalten head(z. B. indem Sie das defanstelle von valdefinieren, um es zu definieren Stream).

Aufgrund der Nachteile von Ansichten sollte dies normalerweise forcenach dem Anwenden der Transformationen geschehen oder als Ansicht beibehalten werden, wenn im Vergleich zur Gesamtgröße der Ansicht nur wenige Elemente erwartet werden, die jemals abgerufen werden.

Daniel C. Sobral
quelle
10
Iteratorist auch ziemlich praktisch, um das Unendliche zu untersuchen, und ich bevorzuge sie im Allgemeinen Streams, wo dies möglich ist. Der eigentliche Vorteil von Streams besteht darin, dass zuvor aufgerufene Werte zwischengespeichert werden. Dies ist ein schwerwiegender Segen, wenn versucht wird, so etwas wie die Fibonacci-Sequenz zu implementieren, die anhand vorheriger Werte definiert wird.
Kevin Wright
5
Fibonacci ist ein weniger als perfektes Beispiel, da es nur die letzten 2 vorherigen Werte benötigt und das Halten des gesamten Streams eine Verschwendung ist. Die Ackermann-Funktion ist wahrscheinlich das kanonische Beispiel.
Jürgen Strobel
4
@ JürgenStrobel Ackermann würde zu einer miesen Leistung führen, da der indizierte Zugriff auf Streams O (n) ist. Aber ich stimme Fibonacci zu.
Daniel C. Sobral
9
Oh, richtig. Dies macht Stream zu einer schlechten Wahl für jeden Caching-Ansatz.
Jürgen Strobel
7
Diese Antwort ist super klar, sie sollte Teil der Dokumentation sein ... oh, eigentlich ist es das! Vielen Dank, Daniel docs.scala-lang.org/tutorials/FAQ/stream-view-iterator.html
Svend