Im Allgemeinen wenden alle 6-fach-Funktionen einen binären Operator auf jedes Element einer Sammlung an. Das Ergebnis jedes Schritts wird an den nächsten Schritt weitergegeben (als Eingabe für eines der beiden Argumente des Binäroperators). Auf diese Weise können wir ein Ergebnis kumulieren .
reduceLeft
und reduceRight
kumulieren ein einzelnes Ergebnis.
foldLeft
und foldRight
kumulieren Sie ein einzelnes Ergebnis mit einem Startwert.
scanLeft
und scanRight
eine Sammlung von kumulativen Zwischenergebnissen unter Verwendung eines Startwerts kumulieren.
Akkumulieren
Von LINKS und vorwärts ...
Mit einer Sammlung von Elementen abc
und einem binären Operator können add
wir untersuchen, was die verschiedenen Faltfunktionen tun, wenn Sie vom linken Element der Sammlung (von A nach C) vorwärts gehen:
val abc = List("A", "B", "C")
def add(res: String, x: String) = {
println(s"op: $res + $x = ${res + x}")
res + x
}
abc.reduceLeft(add)
// op: A + B = AB
// op: AB + C = ABC // accumulates value AB in *first* operator arg `res`
// res: String = ABC
abc.foldLeft("z")(add) // with start value "z"
// op: z + A = zA // initial extra operation
// op: zA + B = zAB
// op: zAB + C = zABC
// res: String = zABC
abc.scanLeft("z")(add)
// op: z + A = zA // same operations as foldLeft above...
// op: zA + B = zAB
// op: zAB + C = zABC
// res: List[String] = List(z, zA, zAB, zABC) // maps intermediate results
Von RECHTS und rückwärts ...
Wenn wir mit dem RIGHT-Element beginnen und rückwärts gehen (von C nach A), werden wir feststellen, dass jetzt das zweite Argument für unseren binären Operator das Ergebnis akkumuliert (der Operator ist der gleiche, wir haben nur die Argumentnamen geändert, um ihre Rollen zu verdeutlichen ):
def add(x: String, res: String) = {
println(s"op: $x + $res = ${x + res}")
x + res
}
abc.reduceRight(add)
// op: B + C = BC
// op: A + BC = ABC // accumulates value BC in *second* operator arg `res`
// res: String = ABC
abc.foldRight("z")(add)
// op: C + z = Cz
// op: B + Cz = BCz
// op: A + BCz = ABCz
// res: String = ABCz
abc.scanRight("z")(add)
// op: C + z = Cz
// op: B + Cz = BCz
// op: A + BCz = ABCz
// res: List[String] = List(ABCz, BCz, Cz, z)
.
Entkumulieren
Von LINKS und vorwärts ...
Wenn stattdessen waren wir de-kumulieren von dem Elemente LEFT einiges Ergebnis durch Subtraktion einer Sammlung beginnen, würden wir das Ergebnis durch das erste Argument kumulieren res
unseren Binäroperators minus
:
val xs = List(1, 2, 3, 4)
def minus(res: Int, x: Int) = {
println(s"op: $res - $x = ${res - x}")
res - x
}
xs.reduceLeft(minus)
// op: 1 - 2 = -1
// op: -1 - 3 = -4 // de-cumulates value -1 in *first* operator arg `res`
// op: -4 - 4 = -8
// res: Int = -8
xs.foldLeft(0)(minus)
// op: 0 - 1 = -1
// op: -1 - 2 = -3
// op: -3 - 3 = -6
// op: -6 - 4 = -10
// res: Int = -10
xs.scanLeft(0)(minus)
// op: 0 - 1 = -1
// op: -1 - 2 = -3
// op: -3 - 3 = -6
// op: -6 - 4 = -10
// res: List[Int] = List(0, -1, -3, -6, -10)
Von RECHTS und rückwärts ...
Aber achten Sie jetzt auf die xRight-Variationen! Denken Sie daran, dass der (de-) kumulierte Wert in den xRight-Variationen an den zweiten Parameter res
unseres Binäroperators übergeben wird minus
:
def minus(x: Int, res: Int) = {
println(s"op: $x - $res = ${x - res}")
x - res
}
xs.reduceRight(minus)
// op: 3 - 4 = -1
// op: 2 - -1 = 3 // de-cumulates value -1 in *second* operator arg `res`
// op: 1 - 3 = -2
// res: Int = -2
xs.foldRight(0)(minus)
// op: 4 - 0 = 4
// op: 3 - 4 = -1
// op: 2 - -1 = 3
// op: 1 - 3 = -2
// res: Int = -2
xs.scanRight(0)(minus)
// op: 4 - 0 = 4
// op: 3 - 4 = -1
// op: 2 - -1 = 3
// op: 1 - 3 = -2
// res: List[Int] = List(-2, 3, -1, 4, 0)
Die letzte Liste (-2, 3, -1, 4, 0) ist vielleicht nicht das, was Sie intuitiv erwarten würden!
Wie Sie sehen, können Sie überprüfen, was Ihr foldX tut, indem Sie stattdessen einfach einen scanX ausführen und das kumulierte Ergebnis bei jedem Schritt debuggen.
Endeffekt
- Kumulieren Sie ein Ergebnis mit
reduceLeft
oder reduceRight
.
- Kumulieren Sie ein Ergebnis mit
foldLeft
oder foldRight
wenn Sie einen Startwert haben.
Kumulieren Sie eine Sammlung von Zwischenergebnissen mit scanLeft
oder scanRight
.
Verwenden Sie eine xLeft-Variante, wenn Sie die Sammlung vorwärts durchgehen möchten .
- Verwenden Sie eine xRight-Variante, wenn Sie die Sammlung rückwärts durchgehen möchten .