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

posted @ 2021-01-11 19:32  Leo-Wong  阅读(1722)  评论(0编辑  收藏  举报