avec filtre à la place du filtre

Est-il toujours plus performant d’utiliser withFilter au lieu de filter, lorsque vous appliquez ensuite des fonctions telles que map, flatmap etc.?

Pourquoi seules les cartes, les flatmap et les foreach sont-ils pris en charge? (Les fonctions attendues comme forall / existent aussi)

Des documents de Scala :

Note: la différence entre c filter p et c withFilter p est que la première crée une nouvelle collection, alors que la seconde ne restreint que le domaine des opérations ultérieures de map , flatMap , foreach et withFilter .

Donc, filter prendra la collection d’origine et produira une nouvelle collection, mais withFilter non ssortingctement (c’est-à-dire paresseusement) des valeurs non filtrées aux appels withFilter map / flatMap / withFilter , enregistrant une seconde passe dans la collection (filtrée). Par conséquent, il sera plus efficace lors du passage à ces appels de méthode ultérieurs.

En fait, withFilter est spécialement conçu pour travailler avec des chaînes de ces méthodes, ce qui constitue une solution pour la compréhension. Aucune autre méthode (telle que forall / exists ) n’est requirejse pour cela, elles n’ont donc pas été ajoutées au type de retour withFilter de withFilter .

En plus de l’excellente réponse de Shadowlands , je voudrais apporter un exemple intuitif de la différence entre filter et withFilter .

Considérons le code suivant

 val list = List(1, 2, 3) var go = true val result = for(i <- list; if(go)) yield { go = false i } 

La plupart des gens s'attendent à result que le result soit égal à la List(1) . C’est le cas depuis la Scala 2.8, car la compréhension est traduite en

 val result = list withFilter { case i => go } map { case i => { go = false i } } 

Comme vous pouvez le voir, la traduction convertit la condition en appel à withFilter . Avant Scala 2.8, la compréhension était traduite en quelque chose comme ceci:

 val r2 = list filter { case i => go } map { case i => { go = false i } } 

En utilisant filter , la valeur du result serait assez différente: List(1, 2, 3) . Le fait que nous activions le drapeau go n'a pas d'effet sur le filtre, car le filtre est déjà effectué. Encore une fois, dans Scala 2.8, ce problème est résolu en utilisant withFilter . Lorsque withFilter est utilisé, la condition est évaluée chaque fois qu'un élément est accédé à l'intérieur d'une méthode de map .

Référence : - p.120, Scala en action (couvre Scala 2.10), Manning Publications, Milanjan Raychaudhuri - Les reflections d'Odersky sur la traduction pour la compréhension

La raison principale pour laquelle forall / exist n’est pas implémentée est que le cas d’utilisation est le suivant:

  • vous pouvez paresser appliquer avec filtre à un stream infini / iterable
  • vous pouvez appliquer paresseusement un autre avecFiltre (et encore et encore)

Pour mettre en œuvre forall / existent, nous devons obtenir tous les éléments, en perdant la paresse.

Donc par exemple:

 import scala.collection.AbstractIterator class RandomIntIterator extends AbstractIterator[Int] { val rand = new java.util.Random def next: Int = rand.nextInt() def hasNext: Boolean = true } //rand_integers is an infinite random integers iterator val rand_integers = new RandomIntIterator val rand_naturals = rand_integers.withFilter(_ > 0) val rand_even_naturals = rand_naturals.withFilter(_ % 2 == 0) println(rand_even_naturals.map(identity).take(10).toList) //calling a second time we get //another ten-tuple of random even naturals println(rand_even_naturals.map(identity).take(10).toList) 

Notez que ten_rand_even_naturals est toujours un iterator. Seulement lorsque nous appelons toList, les nombres aléatoires seront générés et filtrés en chaîne.

Notez que map (identity) est équivalent à map (i => i) et qu’il est utilisé ici pour convertir un object withFilter au type d’origine (par exemple, une collection, un stream, un iterator)

Utiliser pour le rendement peut être un travail, par exemple:

 for { e <- col; if e isNotEmpty } yield e.get(0) 

Pour contourner ce problème, vous pouvez implémenter d’autres fonctions uniquement avec map et flatMap .

De plus, cette optimisation est inutile sur les petites collections…