Strumień, widoki i iteratory

136

Jakie są różnice między strumieniami, widokami (SeqView) i iteratorami w scali? To jest moje zrozumienie:

  • Wszystkie są leniwymi listami.
  • Strumienie buforują wartości.
  • Iteratory mogą być użyte tylko raz? Nie możesz wrócić do początku i ponownie oszacować wartości?
  • Wartości widoku nie są zapisywane w pamięci podręcznej, ale można je wielokrotnie oceniać?

Jeśli więc chcę zaoszczędzić miejsce na stosie, czy powinienem używać iteratorów (jeśli nie będę ponownie przechodzić przez listę) lub widoków? Dzięki.

JWC
źródło
7
Odpowiedziałem na to wcześniej, ale jak to znaleźć? westchnienie ...
Daniel C. Sobral

Odpowiedzi:

182

Po pierwsze, wszystkie nie są rygorystyczne . Ma to szczególne znaczenie matematyczne związane z funkcjami, ale zasadniczo oznacza, że ​​są one obliczane na żądanie, a nie z góry.

Streamto rzeczywiście leniwa lista. W rzeczywistości w Scali a Streamjest, Listktórego tailjestlazy val . Po obliczeniu wartość pozostaje obliczona i jest ponownie wykorzystywana. Lub, jak mówisz, wartości są buforowane.

Można Iteratorużyć tylko raz, ponieważ jest wskaźnikiem przechodzenia do kolekcji, a nie kolekcją samą w sobie. To, co czyni go wyjątkowym w Scali, to fakt, że możesz zastosować transformację taką jak mapi filteri po prostu uzyskać nową, Iteratorktóra zastosuje te transformacje tylko wtedy, gdy poprosisz o następny element.

Scala dostarczała iteratory, które można zresetować, ale jest to bardzo trudne do utrzymania w sposób ogólny i nie stworzyli wersji 2.8.0.

Widoki mają być przeglądane podobnie jak widok bazy danych. Jest to seria transformacji, którą stosuje się do kolekcji w celu stworzenia kolekcji „wirtualnej”. Jak powiedziałeś, wszystkie transformacje są ponownie stosowane za każdym razem, gdy musisz pobrać z nich elementy.

Zarówno Iteratorwidoki, jak i widoki mają doskonałą charakterystykę pamięci. Streamjest fajny, ale w Scali jego główną zaletą jest pisanie nieskończonych sekwencji (szczególnie sekwencji definiowanych rekurencyjnie). Można jednak uniknąć przechowywania całego the Streamw pamięci, upewniając się, że nie przechowujesz odniesienia do jego head(na przykład używając defzamiast valdefiniowania Stream).

Ze względu na kary, jakie ponoszą widoki, zazwyczaj należy to forcezrobić po zastosowaniu transformacji lub zachować jako widok, jeśli oczekuje się, że tylko kilka elementów zostanie kiedykolwiek pobranych, w porównaniu do całkowitego rozmiaru widoku.

Daniel C. Sobral
źródło
10
Iteratorjest również bardzo przydatny do badania nieskończoności i generalnie wolę je od strumieni, jeśli to możliwe. Prawdziwą zaletą strumieni jest to, że wcześniej dostępne wartości są buforowane, co jest poważnym dobrodziejstwem, gdy próbuje się zaimplementować coś w rodzaju sekwencji Fibonacciego - która jest zdefiniowana w kategoriach poprzednich wartości.
Kevin Wright
5
Fibonacci jest mniej niż doskonałym przykładem, ponieważ potrzebuje tylko ostatnich 2 poprzednich wartości, a utrzymanie całego strumienia jest marnotrawstwem. Funkcja Ackermanna jest prawdopodobnie przykładem kanonicznym.
Jürgen Strobel
4
@ JürgenStrobel Ackermann skutkowałoby kiepską wydajnością, ponieważ indeksowany dostęp do strumieni to O (n). Ale zgadzam się z Fibonacci.
Daniel C. Sobral
9
No tak. To sprawia, że ​​Stream jest złym wyborem dla każdego podejścia do buforowania.
Jürgen Strobel
7
Ta odpowiedź jest bardzo jasna, powinna być częścią dokumentacji ... o, właściwie jest! Dzięki Daniel docs.scala-lang.org/tutorials/FAQ/stream-view-iterator.html
Svend