Когда я должен использовать reduceLeft
, reduceRight
, метод использовать-foldleft
, foldRight
, scanLeft
или scanRight
?
Я хочу, чтобы интуиция/обзор свои разногласия - возможно, с некоторыми простыми примерами.
В общем, все 6 раз функции применить двоичный оператор к каждому элементу коллекции. Результат каждого шага передается на следующий этап (в качестве входных данных для одного из бинарный оператор'с двумя аргументами). Таким образом, мы можем кумулировать результат.
reduceLeft
и reduceRight
кумуляция единый результат.
метод использовать-foldleft и foldRight
кумуляция один результат, используя начальное значение.
scanLeft " и " scanRight
кумуляция совокупность промежуточных итоговых результатов с использованием начального значения.
Слева и вперед...
С элементами коллекции " ABC " и бинарного оператора добавить
мы можем исследовать то, что различные фолд функции, когда идешь вперед от левого элемента коллекции (из 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
<БР> Справа и назад...
Если мы начнем с правильным элементом и идти в обратном направлении (из С В А) мы'заметите, что теперь на второй аргумент в нашу бинарный оператор накапливает результат (оператор тот же, просто поменялись имена аргументов, чтобы заставить их роль ясна):
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)
Слева и вперед...
Если вместо этого мы были в де-кумулировать какой результат вычитания, начиная слева элемент коллекции, мы хотели суммировать результат через первый аргумент " Рес " нашего бинарного оператора минус
:
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 передается второй параметр " Рес " нашего бинарного оператора минус
:
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, если вы хотите пойти назад через коллекции.
Как правило, уменьшить,сложить,метод сканирования работает, накапливая сведения о левый и держать на изменение правильной переменной. Основное различие между ними уменьшить,складка:-
Фолд всегда будет начинаться с семян
, т. е. значение определяется пользователем начального значения.
Сокращения будут бросать исключение, если коллекция пуста, где как раз возвращает значение семян. Всегда приведет к одному значению.
Сканирование используется для какой-то порядок обработки элементов из левой или правой стороны, то мы можем использовать предыдущий результат в последующих расчетов. Это означает, что можно сканировать предметы. Всегда приведет к коллекции.
Способ LEFT_REDUCE работает аналогично уменьшить способ.
RIGHT_REDUCE напротив reduceLeft один, т. е. он накапливает значения в правом и держать на изменение левой переменной.
reduceLeftOption и reduceRightOption похожи на left_reduce и right_reduce только разницей, что они возвращают результаты в объект параметров.
Часть вывода для ниже указанного кодекса будут :-
используя "скан" операции над списком чисел (используя семя
значение 0
) список(-2,-1,0,1,2)
{0,-2}=>-2 {-2,-1}=>-3 {-3,0}=>-3 {-3,1}=>-2 {-2,2}=>0 сканирования(0, -2, -3, -3, -2, 0)
{0,-2}=>-2 {-2,-1}=>-3 {-3,0}=>-3 {-3,1}=>-2 {-2,2}=>0 scanLeft (а+б) список(0, -2, -3, -3, -2, 0)
{0,-2}=>-2 {-2,-1}=>-3 {-3,0}=>-3 {-3,1}=>-2 {-2,2}=>0 scanLeft (Б+а) список(0, -2, -3, -3, -2, 0)
{2,0}=>2 {1,2}=>3 {0,3}=>3 {-1,3}=>2 {-2,2}=>0 scanRight (а+б) список(0, 2, 3, 3, 2, 0)
{2,0}=>2 {1,2}=>3 {0,3}=>3 {-1,3}=>2 {-2,2}=>0 scanRight (Б+а) список(0, 2, 3, 3, 2, 0)
используя уменьшить
,сброс
операции над списком строк списка("А", то"в”, на"в себе", то"Д" В, С"Е", у)`
Код :
object ScanFoldReduce extends App {
val list = List("A","B","C","D","E")
println("reduce (a+b) "+list.reduce((a,b)=>{
print("{"+a+","+b+"}=>"+ (a+b)+" ")
a+b
}))
println("reduceLeft (a+b) "+list.reduceLeft((a,b)=>{
print("{"+a+","+b+"}=>"+ (a+b)+" ")
a+b
}))
println("reduceLeft (b+a) "+list.reduceLeft((a,b)=>{
print("{"+a+","+b+"}=>"+ (b+a)+" " )
b+a
}))
println("reduceRight (a+b) "+list.reduceRight((a,b)=>{
print("{"+a+","+b+"}=>"+ (a+b)+" " )
a+b
}))
println("reduceRight (b+a) "+list.reduceRight((a,b)=>{
print("{"+a+","+b+"}=>"+ (b+a)+" ")
b+a
}))
println("scan "+list.scan("[")((a,b)=>{
print("{"+a+","+b+"}=>"+ (a+b)+" " )
a+b
}))
println("scanLeft (a+b) "+list.scanLeft("[")((a,b)=>{
print("{"+a+","+b+"}=>"+ (a+b)+" " )
a+b
}))
println("scanLeft (b+a) "+list.scanLeft("[")((a,b)=>{
print("{"+a+","+b+"}=>"+ (b+a)+" " )
b+a
}))
println("scanRight (a+b) "+list.scanRight("[")((a,b)=>{
print("{"+a+","+b+"}=>"+ (a+b)+" " )
a+b
}))
println("scanRight (b+a) "+list.scanRight("[")((a,b)=>{
print("{"+a+","+b+"}=>"+ (b+a)+" " )
b+a
}))
//Using numbers
val list1 = List(-2,-1,0,1,2)
println("reduce (a+b) "+list1.reduce((a,b)=>{
print("{"+a+","+b+"}=>"+ (a+b)+" ")
a+b
}))
println("reduceLeft (a+b) "+list1.reduceLeft((a,b)=>{
print("{"+a+","+b+"}=>"+ (a+b)+" ")
a+b
}))
println("reduceLeft (b+a) "+list1.reduceLeft((a,b)=>{
print("{"+a+","+b+"}=>"+ (b+a)+" " )
b+a
}))
println(" reduceRight (a+b) "+list1.reduceRight((a,b)=>{
print("{"+a+","+b+"}=>"+ (a+b)+" " )
a+b
}))
println(" reduceRight (b+a) "+list1.reduceRight((a,b)=>{
print("{"+a+","+b+"}=>"+ (b+a)+" ")
b+a
}))
println("scan "+list1.scan(0)((a,b)=>{
print("{"+a+","+b+"}=>"+ (a+b)+" " )
a+b
}))
println("scanLeft (a+b) "+list1.scanLeft(0)((a,b)=>{
print("{"+a+","+b+"}=>"+ (a+b)+" " )
a+b
}))
println("scanLeft (b+a) "+list1.scanLeft(0)((a,b)=>{
print("{"+a+","+b+"}=>"+ (b+a)+" " )
b+a
}))
println("scanRight (a+b) "+list1.scanRight(0)((a,b)=>{
print("{"+a+","+b+"}=>"+ (a+b)+" " )
a+b}))
println("scanRight (b+a) "+list1.scanRight(0)((a,b)=>{
print("{"+a+","+b+"}=>"+ (a+b)+" " )
b+a}))
}