Загалом, всі 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, якщо хочете повернутися назад по колекції.