Stream vs Views vs Iterators

136

Quais são as diferenças entre Streams, Views (SeqView) e Iterators no scala? Este é o meu entendimento:

  • São todas listas preguiçosas.
  • Os fluxos armazenam em cache os valores.
  • Iteradores podem ser usados ​​apenas uma vez? Você não pode voltar ao início e avaliar o valor novamente?
  • Os valores da visualização não são armazenados em cache, mas você pode avaliá-los repetidamente?

Portanto, se eu quiser economizar espaço de heap, devo usar iteradores (se não percorrer a lista novamente) ou visualizações? Obrigado.

JWC
fonte
7
Eu já respondi isso antes, mas como encontrá-lo? suspiro ...
Daniel C. Sobral

Respostas:

182

Primeiro, eles são todos não rigorosos . Isso tem um significado matemático específico relacionado às funções, mas, basicamente, significa que elas são computadas sob demanda e não antecipadamente.

Streamé realmente uma lista preguiçosa. De fato, em Scala, a Streamé um Listcujo tailé a lazy val. Uma vez calculado, um valor permanece calculado e é reutilizado. Ou, como você diz, os valores são armazenados em cache.

Um Iteratorsó pode ser usado uma vez porque é um ponteiro transversal para uma coleção, e não uma coleção em si. O que o torna especial em Scala é o fato de que você pode aplicar de transformação, como mape filtere simplesmente obter um novo Iteratorque só irá aplicar essas transformações quando você perguntar para o próximo elemento.

O Scala costumava fornecer iteradores que poderiam ser redefinidos, mas isso é muito difícil de suportar de uma maneira geral, e eles não criaram a versão 2.8.0.

As visualizações devem ser vistas como uma exibição de banco de dados. É uma série de transformação que se aplica a uma coleção para produzir uma coleção "virtual". Como você disse, todas as transformações são reaplicadas sempre que você precisar buscar elementos nela.

Ambas as Iteratorvisualizações e têm excelentes características de memória. Streamé bom, mas, em Scala, seu principal benefício é escrever sequências infinitas (particularmente sequências definidas recursivamente). Um pode evitar manter todas as Streamna memória, no entanto, por ter certeza que você não manter uma referência ao seu head(por exemplo, usando defem vez de valdefinir o Stream).

Por causa das penalidades incorridas pelas visualizações, geralmente forceé necessário após a aplicação das transformações, ou mantê-la como uma visualização, se é esperado que apenas alguns elementos sejam buscados, em comparação com o tamanho total da visualização.

Daniel C. Sobral
fonte
10
Iteratortambém é bastante útil para investigar o infinito, e geralmente os prefiro sobre fluxos sempre que possível. O benefício real nos fluxos é que os valores acessados ​​anteriormente são armazenados em cache, o que é um benefício sério ao tentar implementar algo como a sequência de fibonacci - que é definida em termos de valores anteriores.
Kevin Wright
5
Fibonacci é um exemplo menos do que perfeito, pois precisa apenas dos 2 últimos valores anteriores e manter todo o fluxo é um desperdício. A função Ackermann é provavelmente o exemplo canônico.
Jürgen Strobel
4
@ JürgenStrobel Ackermann resultaria em péssimo desempenho, já que o acesso indexado aos fluxos é O (n). Mas concordo com fibonacci.
Daniel C. Sobral
9
Oh, certo. Isso faz do Stream uma má escolha para qualquer abordagem de cache.
Jürgen Strobel
7
Essa resposta é super clara, deve fazer parte da documentação ... ah, na verdade é! Graças Daniel docs.scala-lang.org/tutorials/FAQ/stream-view-iterator.html
Svend