Quand devrais-je utiliser reduceLeft
, reduceRight
, foldLeft
, foldRight
, scanLeft
ou scanRight
?
Je veux une intuition / aperçu de leurs différences - éventuellement avec quelques exemples simples.
Quand devrais-je utiliser reduceLeft
, reduceRight
, foldLeft
, foldRight
, scanLeft
ou scanRight
?
Je veux une intuition / aperçu de leurs différences - éventuellement avec quelques exemples simples.
En général, tous les 6 fois les fonctions d'appliquer un opérateur binaire à chaque élément d'une collection. Le résultat de chaque étape est passée à l'étape suivante (en tant qu'entrée à l'un des opérateur binaire de deux arguments). De cette façon, nous pouvons cumuler un résultat.
reduceLeft
et reduceRight
cumuler un résultat unique.
foldLeft
et foldRight
cumuler un résultat unique à l'aide d'une valeur de départ.
scanLeft
et scanRight
cumuler une collection d'intermédiaires résultats cumulés à l'aide d'une valeur de départ.
À partir de la GAUCHE et vers l'avant...
Avec une collection d'éléments abc
et un opérateur binaire add
nous pouvons explorer les différentes fois les fonctions de faire lorsque l'on va vers l'avant de la GAUCHE de l'élément de la collection (de A à C):
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
De la DROITE et vers l'arrière...
Si nous commençons avec le DROIT de l'élément et de revenir en arrière (de C à A) on remarquera que, maintenant, la deuxième argument à notre opérateur binaire s'accumule le résultat (l'opérateur est le même, nous avons juste changé le nom des arguments à faire leurs rôles clair):
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)
.
À partir de la GAUCHE et vers l'avant...
Si, au contraire, nous avons été à de cumuler un résultat par soustraction, en partant de la GAUCHE élément d'une collection, il nous serait possible de cumuler le résultat par le premier argument res
de notre opérateur binaire 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)
De la DROITE et vers l'arrière...
Mais regarder dehors pour le xRight variations maintenant! Rappelez-vous que la (-) valeur cumulée dans le xRight variations est passé à la deuxième paramètre res
de notre opérateur binaire 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)
Le dernier de la Liste(-2, 3, -1, 4, 0) est peut-être pas ce que vous attendez!
Comme vous le voyez, vous pouvez vérifier que votre foldX est fait par la simple exécution d'un scanX au lieu et déboguer le résultat cumulé à chaque étape.
reduceLeft
ou reduceRight
.foldLeft
ou foldRight
si vous avez une valeur de départ.Cumuler une collection de résultats intermédiaires avec scanLeft
ou scanRight
.
Utiliser un xLeft variation si vous voulez aller transmet par le biais de la collection.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.