Загалом, всі 6-кратні функції застосовують двійковий оператор до кожного елемента колекції. Результат кожного кроку передається на наступний крок (як вхід до одного з двох аргументів двійкового оператора). Таким чином ми можемо накопичити результат.
reduceLeftі reduceRightпідсумувати єдиний результат.
foldLeftі foldRightкумулювати єдиний результат, використовуючи стартове значення.
scanLeftі scanRightкумулювати сукупність проміжних кумулятивних результатів, використовуючи початкове значення.
Накопичуватися
Зліва і вперед ...
За допомогою набору елементів abcта двійкового оператора addми можемо дослідити, що виконують різні функції складання, коли рухаються вперед від лівого елемента колекції (від А до С):
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
З правого боку та назад ...
Якщо ми почнемо з елемента ПРАВО і повернемось назад (від C до A), ми помітимо, що тепер другий аргумент для нашого бінарного оператора накопичує результат (оператор той самий, ми просто переключили назви аргументів, щоб зрозуміти їх ролі ):
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)
.
Декупаж
Зліва і вперед ...
Якщо б замість цього ми декумулювали якийсь результат шляхом віднімання, починаючи з елемента ЛІВО колекції, ми би накопичили результат за допомогою першого аргументу resнашого двійкового оператора 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)
З правого боку та назад ...
Але дивіться на варіанти xRight зараз! Пам'ятайте, що (де) накопичене значення у варіаціях xRight передається другому параметру resнашого двійкового оператора 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)
Останній Список (-2, 3, -1, 4, 0) - це, можливо, не те, що ви інтуїтивно очікували б!
Як бачите, ви можете перевірити, що робить ваш foldX, просто запустивши ScanX замість цього і налагоджуйте накопичений результат на кожному кроці.
Нижня лінія
- Підсумовуйте результат за допомогою
reduceLeftабо reduceRight.
- Підсумовуйте результат за допомогою стартового значення
foldLeftабо, foldRightякщо у вас є.
Накопичуйте колекцію проміжних результатів за допомогою scanLeftабо scanRight.
Скористайтеся варіантом xLeft, якщо ви хочете перейти вперед по колекції.
- Скористайтеся варіантом xRight, якщо хочете повернутися назад по колекції.