Flux vs vues vs itérateurs

136

Quelles sont les différences entre les flux, les vues (SeqView) et les itérateurs dans scala? Voici ma compréhension:

  • Ce sont toutes des listes paresseuses.
  • Les flux mettent en cache les valeurs.
  • Les itérateurs ne peuvent être utilisés qu'une seule fois? Vous ne pouvez pas revenir au début et évaluer à nouveau la valeur?
  • Les valeurs de View ne sont pas mises en cache mais vous pouvez les évaluer encore et encore?

Donc, si je veux économiser de l'espace sur le tas, dois-je utiliser des itérateurs (si je ne traverse pas à nouveau la liste) ou des vues? Merci.

JWC
la source
7
J'ai déjà répondu à cela, mais comment le trouver? soupir ...
Daniel C. Sobral

Réponses:

182

Premièrement, ils sont tous non stricts . Cela a une signification mathématique particulière liée aux fonctions, mais signifie essentiellement qu'elles sont calculées à la demande plutôt qu'à l'avance.

Streamest en effet une liste paresseuse. En fait, dans Scala, a Streamest un Listdont tailest a lazy val. Une fois calculée, une valeur reste calculée et est réutilisée. Ou, comme vous le dites, les valeurs sont mises en cache.

An Iteratorne peut être utilisé qu'une seule fois car il s'agit d'un pointeur de parcours vers une collection et non d'une collection en soi. Ce qui le rend spécial dans Scala est le fait que vous pouvez appliquer une transformation telle que mapet filteret simplement en obtenir une nouvelle Iteratorqui n'appliquera ces transformations que lorsque vous demanderez l'élément suivant.

Scala avait l'habitude de fournir des itérateurs qui pouvaient être réinitialisés, mais c'est très difficile à supporter d'une manière générale, et ils n'ont pas fait la version 2.8.0.

Les vues sont censées être affichées comme une vue de base de données. C'est une série de transformation que l'on applique à une collection pour produire une collection «virtuelle». Comme vous l'avez dit, toutes les transformations sont réappliquées chaque fois que vous devez en extraire des éléments.

Les deux Iteratorvues ont d'excellentes caractéristiques de mémoire. Streamc'est bien, mais, en Scala, son principal avantage est d'écrire des séquences infinies (en particulier des séquences définies de manière récursive). On peut cependant éviter de garder tout le Streamen mémoire, en s'assurant de ne pas garder une référence à son head(par exemple, en utilisant defau lieu de valpour définir le Stream).

En raison des pénalités encourues par les vues, il convient généralement de forcele conserver après l'application des transformations, ou de le conserver en tant que vue si seuls quelques éléments sont censés être extraits, par rapport à la taille totale de la vue.

Daniel C. Sobral
la source
10
Iteratorest également très pratique pour sonder l'infini, et je les préfère généralement aux flux lorsque cela est possible. Le véritable avantage des flux est que les valeurs précédemment accédées sont mises en cache, ce qui est un sérieux avantage lorsque vous essayez d'implémenter quelque chose comme la séquence fibonacci - qui est définie en termes de valeurs précédentes.
Kevin Wright
5
Fibonacci est un exemple loin d'être parfait car il n'a besoin que des 2 dernières valeurs précédentes, et conserver l'ensemble du flux est un gaspillage. La fonction Ackermann est probablement l'exemple canonique.
Jürgen Strobel
4
@ JürgenStrobel Ackermann entraînerait des performances médiocres, puisque l'accès indexé des flux est O (n). Mais je suis d'accord avec fibonacci.
Daniel
9
Oh oui. Cela fait de Stream un mauvais choix pour toute approche de mise en cache.
Jürgen Strobel
7
Cette réponse est super claire, elle devrait faire partie de la documentation ... oh, en fait ça l'est! Merci Daniel docs.scala-lang.org/tutorials/FAQ/stream-view-iterator.html
Svend