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)
Von die Scala-Dokumente :
Hinweis: Der Unterschied zwischen
c filter p
undc withFilter p
besteht darin, dass der vorherige erstellt eine neue Sammlung, während letztere nur die Domäne von .__ einschränkt. nachfolgendemap
-,flatMap
-,foreach
- undwithFilter
-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.
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
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.
Der Hauptgrund dafür, dass forall/exists nicht implementiert ist, besteht darin, dass der Anwendungsfall folgendermaßen lautet:
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)