it-swarm.com.de

withFilter statt filter

Ist die Verwendung von Filter anstelle von Filtern immer leistungsfähiger, wenn anschließend Funktionen wie Map, Flatmap usw. angewendet werden?

Warum werden nur Map, Flatmap und Foreach unterstützt? (Erwartete Funktionen wie forall/gibt es auch) 

68
Kigyo

Von die Scala-Dokumente :

Hinweis: Der Unterschied zwischen c filter p und c withFilter p besteht darin, dass der vorherige erstellt eine neue Sammlung, während letztere nur die Domäne von .__ einschränkt. nachfolgende map-, flatMap-, foreach- und withFilter-Vorgänge.

filter nimmt also die ursprüngliche Sammlung und erzeugt eine neue Sammlung, aber withFilter leitet nicht gefilterte Werte nicht strikt (d. H. Träge) an spätere map/flatMap/withFilter-Aufrufe weiter, wodurch ein zweiter Durchlauf durch die (gefilterte) Sammlung gesichert wird. Daher ist es effizienter, wenn Sie zu diesen nachfolgenden Methodenaufrufen weitergeleitet werden.

Tatsächlich ist withFilter speziell für das Arbeiten mit Ketten dieser Methoden konzipiert, in die ein Verständnis hineingezogen wird. Dazu sind keine anderen Methoden (wie forall/exists) erforderlich, daher wurden sie nicht zum FilterMonadic-Rückgabetyp von withFilter hinzugefügt. 

105
Shadowlands

Zusätzlich zu der hervorragenden Antwort von Shadowlands möchte ich ein intuitives Beispiel für den Unterschied zwischen filter und withFilter geben.

Betrachten wir den folgenden Code

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

Die meisten Leute erwarten, dass result gleich List(1) ist. Dies ist seit Scala 2.8 der Fall, weil das Verstehen in übersetzt wird

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

Wie Sie sehen, konvertiert die Übersetzung die Bedingung in einen Aufruf von withFilter. In der früheren Scala 2.8 wurde Verständnis für Folgendes verstanden:

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

Mit filter wäre der Wert von result ziemlich unterschiedlich: List(1, 2, 3) Die Tatsache, dass wir das go-Flag false machen, hat keine Auswirkungen auf den Filter, da der Filter bereits ausgeführt wird. In Scala 2.8 wird dieses Problem erneut mit withFilter gelöst. Wenn withFilter verwendet wird, wird die Bedingung jedes Mal ausgewertet, wenn auf ein Element innerhalb einer map-Methode zugegriffen wird.

Referenz: - S.120, Scala in Aktion (deckt Scala 2.10 ab), Manning Publications, Milanjan Raychaudhuri - Oderskys Gedanken zur Übersetzung nach dem Verständnis

5
ZenLulz

Für den gesamten/vorhandenen Teil:

someList.filter(conditionA).forall(conditionB)

wäre das gleiche wie (wenn auch ein bisschen unintuitiv)

!someList.exists(conditionA && !conditionB)

Ebenso kann .filter (). Exists () zu einem exists () Check kombiniert werden.

0
lznt

Der Hauptgrund dafür, dass forall/exists nicht implementiert ist, besteht darin, dass der Anwendungsfall folgendermaßen lautet:

  • sie können träge mitFilter auf einen unendlichen Stream/Iterable anwenden
  • sie können faul ein anderes mitFilter anwenden (und immer wieder) 

Um forall/exists zu implementieren, müssen wir alle Elemente beschaffen und die Faulheit verlieren.

Also zum Beispiel:

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)

Beachten Sie, dass ten_Rand_even_naturals immer noch ein Iterator ist. Nur Wenn wir toList aufrufen, werden die Zufallszahlen generiert und in einer Kette gefiltert

Beachten Sie, dass map (identity) äquivalent zu map (i => i) ist und hier verwendet wird, um ein withFilter-Objekt zurück in den ursprünglichen Typ zu konvertieren (z. B. eine Sammlung, ein Stream, ein Iterator)

0
frhack