Stream vs Views vs Iterators


136

Quali sono le differenze tra stream, viste (SeqView) e iteratori in scala? Questa è la mia comprensione:

  • Sono tutti elenchi pigri.
  • I flussi memorizzano nella cache i valori.
  • Gli iteratori possono essere utilizzati solo una volta? Non puoi tornare all'inizio e valutare di nuovo il valore?
  • I valori della vista non vengono memorizzati nella cache ma è possibile valutarli ancora e ancora?

Quindi, se voglio risparmiare spazio su heap, dovrei usare gli iteratori (se non dovrò attraversare di nuovo l'elenco) o le viste? Grazie.


7
Ho già risposto prima, ma come trovarlo? sospiro ...
Daniel C. Sobral

Risposte:


182

Innanzitutto, sono tutti non severi . Questo ha un significato matematico particolare legato alle funzioni, ma, fondamentalmente, significa che sono calcolate su richiesta anziché in anticipo.

Streamè davvero una lista pigra. In effetti, a Scala, a Streamè a di Listcui tailè a lazy val. Una volta calcolato, un valore rimane calcolato e viene riutilizzato. Oppure, come dici tu, i valori vengono memorizzati nella cache.

An Iteratorpuò essere usato una sola volta perché è un puntatore a croce in una raccolta e non una raccolta in sé. Ciò che lo rende speciale a Scala è il fatto che è possibile applicare la trasformazione, come mape filtere semplicemente ottenere un nuovo Iteratorche si applicano soltanto queste trasformazioni quando si chiede l'elemento successivo.

Scala forniva iteratori che potevano essere ripristinati, ma che è molto difficile da supportare in modo generale, e non hanno realizzato la versione 2.8.0.

Le viste devono essere visualizzate in modo molto simile a una vista del database. È una serie di trasformazione che si applica a una raccolta per produrre una raccolta "virtuale". Come hai detto, tutte le trasformazioni vengono riapplicate ogni volta che è necessario recuperarne gli elementi.

Entrambe Iteratore le viste hanno eccellenti caratteristiche di memoria. Streamè bello, ma, alla Scala, il suo principale vantaggio è scrivere infinite sequenze (in particolare sequenze definite in modo ricorsivo). Si può evitare di mantenere tutto Streamin memoria, tuttavia, assicurandosi di non mantenere un riferimento al suo head(ad esempio, usando definvece di valdefinire il Stream).

A causa delle penalità subite dalle viste, di solito forcesi dovrebbe farlo dopo aver applicato le trasformazioni o tenerlo come una vista se si prevede che solo pochi elementi verranno recuperati, rispetto alla dimensione totale della vista.


10
Iteratorè anche molto utile per sondare l'infinito, e generalmente li preferisco ai flussi ove possibile. Il vero vantaggio nei flussi è che i valori precedentemente accessibili sono memorizzati nella cache, il che è un grande vantaggio quando si tenta di implementare qualcosa come la sequenza fibonacci - che è definita in termini di valori precedenti.
Kevin Wright,

5
Fibonacci è un esempio meno che perfetto in quanto necessita solo degli ultimi 2 valori precedenti e mantenere l'intero flusso è uno spreco. La funzione di Ackermann è probabilmente l'esempio canonico.
Jürgen Strobel,

4
@ JürgenStrobel Ackermann comporterebbe prestazioni scadenti, poiché l'accesso indicizzato ai flussi è O (n). Ma sono d'accordo con Fibonacci.
Daniel C. Sobral,

9
Oh giusto. Questo rende Stream una cattiva scelta per qualsiasi approccio di memorizzazione nella cache.
Jürgen Strobel,

7
Questa risposta è super chiara, dovrebbe essere parte della documentazione ... oh, in realtà lo è! Grazie Daniel docs.scala-lang.org/tutorials/FAQ/stream-view-iterator.html
Svend
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.