Scala之Fold:foldRight()与foldLeft()详解
Fold折叠:化简的一种特殊情况,foldRight():右折叠,foldLeft()左折叠
override /*TraversableLike*/
def foldLeft[B](z: B)(f: (B, A) => B): B = {
var acc = z
var these = this
while (!these.isEmpty) {
acc = f(acc, these.head)
these = these.tail
}
acc
}
释义:
z: B 表示传入一个B[泛型]类型的zero零值
f: (B, A) => B 表示:传入一个名叫f的函数【scala可以将函数当做参数传递】,该函数需要传入两个参数,分别是B、A两种类型的参数,但返回值是B类型,也就是零值类型
foldLeft 函数名,柯理化的函数【参数列表2个:(z: B)、(f: (B, A) => B)】,该函数的返回值也是B类型
示例代码:
package sparkstreaming
object SparkStreamingDemo01 {
def main(args: Array[String]): Unit = {
val list = List(1,2,3,4)
val i = list.foldLeft(1)((x,y)=>x-y)
val i1 = list.foldRight(1)((x,y)=>x-y)
println(i)
println(i1)
}
}
结果:
-9
-1
这两种算法原理究竟是怎样的呢?结果是如何得到的呢?
首先:foldLeft
val list = List(1,2,3,4)
val i = list.foldLeft(1)((x,y)=>x-y)
执行过程是:
第一次循环将零值传入函数f(x,y)=>x-y的左边x的位置,然后取出列表的第一个元素【these.head】,计算:res1 = f(1, 1)=>1-1 == 0 【伪代码】
第二次循环将第一次循环的结果【res1 == 0】继续当做左值传入x的位置,取出列表的第二个元素2放入y的位置,计算:res2 = f(res1, 2)=>0-2 == -2
第二次循环将第一次循环的结果【res2 == -2】继续当做左值传入x的位置,取出列表的第二个元素3放入y的位置,计算:res3 = f(res2, 3)=>-2-3 == -5
第四次循环将第一次循环的结果【res3 == -5】继续当做左值传入x的位置,取出列表的第二个元素4放入y的位置,计算:res4 = f(res3, 4)=>-5-4 == -9
也就是得到最终的结果是:-9
首先:foldRight
val list = List(1,2,3,4)
val i1 = list.foldRight(1)((x,y)=>x-y)
源码:可以看到其实是先将list做了一次翻转,然后还是调用的:foldLeft
1、List(1,2,3,4)翻转得到List(4, 3, 2, 1)
2、此时调用foldLeft参数列表没有变化,但是函数f(x,y)=>y-x,变成了:y-x
执行过程是:
第一次循环将零值传入函数f(x,y)=>x-y的左边x的位置,然后取出反转后的列表的第一个元素4【these.head】,计算:res1 = f(1, 4)=> 4-1 == 3 【伪代码】
第二次循环将第一次循环的结果【res1 == 3】继续当做左值传入x的位置,取出列表的第二个元素3放入y的位置,计算:res2 = f(res1, 3)=> 3-3 == 0
第二次循环将第一次循环的结果【res2 == 0】继续当做左值传入x的位置,取出列表的第二个元素2放入y的位置,计算:res3 = f(res2, 2)=> 2-0 == 2
第四次循环将第一次循环的结果【res3 == 2】继续当做左值传入x的位置,取出列表的第二个元素1放入y的位置,计算:res4 = f(res3, 1)=> 1-2 == -1
也就是得到最终的结果是:-1