Em geral, todas as funções de 6 dobras aplicam um operador binário a cada elemento de uma coleção. O resultado de cada etapa é passado para a próxima etapa (como entrada para um dos dois argumentos do operador binário). Dessa forma, podemos acumular um resultado.
reduceLefte reduceRightacumule um único resultado.
foldLefte foldRightacumule um único resultado usando um valor inicial.
scanLefte scanRightacumule uma coleção de resultados cumulativos intermediários usando um valor inicial.
Acumular
Da esquerda para a frente ...
Com uma coleção de elementos abce um operador binário add, podemos explorar o que as diferentes funções de dobra fazem ao avançar do elemento LEFT da coleção (de A 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
À DIREITA e para trás ...
Se começarmos com o elemento RIGHT e voltarmos (de C para A), perceberemos que agora o segundo argumento para nosso operador binário acumula o resultado (o operador é o mesmo, apenas trocamos os nomes dos argumentos para deixar suas funções claras ):
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)
.
De-acumular
Da esquerda para a frente ...
Se, em vez disso, deduzirmos algum resultado por subtração a partir do elemento LEFT de uma coleção, acumularemos o resultado através do primeiro argumento resdo nosso operador binário 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)
À DIREITA e para trás ...
Mas esteja atento às variações do xRight agora! Lembre-se de que o valor (des-) acumulado nas variações xRight é passado para o segundo parâmetro resdo nosso operador binário 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)
A última lista (-2, 3, -1, 4, 0) talvez não seja o que você esperaria intuitivamente!
Como você vê, você pode verificar o que o seu foldX está fazendo, basta executar um scanX e depurar o resultado acumulado a cada etapa.
Bottom line