withFilter statt Filter

Antworten:

121

Aus den Scala-Dokumenten :

Anmerkung: der Unterschied zwischen c filter pund c withFilter pist , dass erstere eine neue Sammlung erstellt, während nur die letztere den Bereich der nachfolgenden einschränkt map, flatMap, foreachund withFilterOperationen.

So filterwird die ursprüngliche Sammlung nehmen und eine neue Kollektion produzieren, aber withFilterwird nicht streng (dh träge) passiert ungefilterten Werte bis hin zum späteren map/ flatMap/ withFilterAnrufen, einen zweiten Durchlauf durch die (gefilterte) Sammlung speichern. Daher ist es effizienter, wenn diese nachfolgenden Methodenaufrufe weitergeleitet werden.

In der Tat withFilterist speziell für die Arbeit mit Ketten dieser Methoden konzipiert, in die ein zum Verständnis entzuckert wird. Hierfür sind keine anderen Methoden (wie forall/ exists) erforderlich, daher wurden sie nicht zum FilterMonadicRückgabetyp von hinzugefügt withFilter.

Schattenlande
quelle
Ich hoffe, sie fügen diese Methoden eines Tages noch hinzu.
Kigyo
1
@Kigyo Ich glaube nicht, dass du withFilter selbst verwenden sollst (abgesehen davon, dass es implizit in for-Ausdrücken enthalten ist). Verwenden viewSie diese Option, wenn Karten / Filter faul sein sollen.
Luigi Plinge
Aha. Was ist der genaue Unterschied zwischen viewund withFilter? Warum wird die Ansicht nicht verwendet for-loops?
Kigyo
5
Nur als Referenz denke ich, dass Sammlungen - Tipps und Tricks hervorragende Informationen liefern. H5s sind nicht verankert, aber Sie können Don’t create temporary collectionsim verknüpften Bereich suchen .
sthzg
4
Im Hinblick auf die explizite Verwendung von withFilterMartin Odersky selbst nutzt es ausdrücklich in seinen Scala Kursen auf Coursera, die sehr empfehle ich. Wenn er dies tut, kann dies auch anderen Trost geben, obwohl der Unterschied normalerweise nur 1 Zeichen beträgt. Zum Beispiel seq.view filter pvs. seq withFilter p.
Chuck Daniels
9

Neben der hervorragenden Antwort von Shadowlands möchte ich ein intuitives Beispiel für den Unterschied zwischen filterund geben withFilter.

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 Menschen erwarten result, gleich zu sein List(1). Dies ist seit Scala 2.8 der Fall, weil das Verständnis in übersetzt wird

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

Wie Sie sehen können, wandelt die Übersetzung die Bedingung in einen Aufruf von um withFilter. Vor Scala 2.8 wurde das Verständnis in Folgendes übersetzt:

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

Mit wäre filterder Wert von resultziemlich unterschiedlich : List(1, 2, 3). Die Tatsache, dass wir das goFlag erstellen, falsehat keine Auswirkung auf den Filter, da der Filter bereits fertig ist. Auch in Scala 2.8 wird dieses Problem mit gelöst withFilter. Bei withFilterVerwendung wird die Bedingung jedes Mal ausgewertet, wenn auf ein Element innerhalb einer mapMethode zugegriffen wird.

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

ZenLulz
quelle
1

Der Hauptgrund, weil forall / exist nicht implementiert ist, ist, dass der Anwendungsfall folgender ist:

  • Sie können withFilter träge auf einen unendlichen Stream / iterable anwenden
  • Sie können einen anderen mit Filter faul anwenden (und immer wieder)

Um forall / exist zu implementieren, müssen wir alle Elemente erhalten 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 in der Kette generiert und gefiltert

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

frhack
quelle
1

Für den forall / existierenden Teil:

someList.filter(conditionA).forall(conditionB)

wäre das gleiche wie (obwohl ein wenig unintuitiv)

!someList.exists(conditionA && !conditionB)

In ähnlicher Weise kann .filter (). Exists () zu einer exist () -Prüfung kombiniert werden.

lznt
quelle
-3

Die Verwendung für den Ertrag kann eine Problemumgehung sein, zum Beispiel:

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

Um dieses Problem zu umgehen, können Sie andere Funktionen nur mit mapund implementieren flatMap.

Darüber hinaus ist diese Optimierung bei kleinen Sammlungen nutzlos…

Yann Moisan
quelle