Scala reduce fold scan

reduce 化简

将二元函数引用于集合中的函数。

// 源码 reduce
def reduce[A1 >: A](op: (A1, A1) => A1): A1 = reduceLeft(op)

// 源码 reduceLeft
override /*TraversableLike*/
def reduceLeft[B >: A](f: (B, A) => B): B =
if (isEmpty) throw new UnsupportedOperationException("empty.reduceLeft")
else tail.foldLeft[B](head)(f)

// 源码 reduceRight
override /*IterableLike*/
def reduceRight[B >: A](op: (A, B) => B): B =
if (isEmpty) throw new UnsupportedOperationException("Nil.reduceRight")
else if (tail.isEmpty) head
else op(head, tail.reduceRight(op))

需求:val list = List(1, 2, 3, 4 ,5) , 求出list的和。

分析:上面的问题当然可以使用遍历list方法来解决,这里我们使用scala的化简(reduce)方式来完成。

val list = List(1, 2, 3, 4, 5)
//sum 返回两个数的和
def sum(num1: Int, num2: Int): Int = {
  num1 + num2
}
//分析执行流程. 1, 2, 3, 4, 5
//1.(1,2),3,4,5
//2.(3,3),4,5
//3.(6,4),5
//4.(10,5)
//5.15

//((((1, 2), 3, 4), 5)
println(list.reduce(sum))   // 15

//((((1, 2), 3, 4), 5)
println(list.reduceLeft(sum))   // 15

//(1, (20, (30, (4, 5))))
println(list.reduceRight(sum))  // 15

reduceLeft()这个函数的执行逻辑如图

reduceRight() 和上面一样,只是从右边开始进行简化。


fold 折叠

fold函数将上一步返回的值作为函数的第一个参数继续传递参与运算,直到list中的所有元素被遍历。

// 源码 fold
def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1 = foldLeft(z)(op)

// 源码 foldLeft
override /*TraversableLike*/
def foldLeft[B](z: B)(@deprecatedName('f) op: (B, A) => B): B = {
  var acc = z
  var these = this
  while (!these.isEmpty) {
    acc = op(acc, these.head)
    these = these.tail
  }
  acc
}

// 源码 foldRight
override /*IterableLike*/
def foldRight[B](z: B)(@deprecatedName('f) op: (A, B) => B): B =
if (this.isEmpty) z
else op(head, tail.foldRight(z)(op))
  1. 以把 reduceLeft 看做简化版的 foldLeft
  2. 可以看到 reduceLeft 就是调用的 foldLeft[B](head),并且是默认从计划的head元素开始操作的。
// 折叠
val list = List(1, 2, 3, 4)
def minus( num1 : Int, num2 : Int ): Int = {
  num1 - num2
}

// ((((5,1),2),3),4)
println(list.fold(5)(minus))  // -5

// ((((5,1),2),3),4)
println(list.foldLeft(5)(minus))  // -5

// (1,(2,(3,(4,5))))
println(list.foldRight(5)(minus)) // 3

// (20)(1,2,3,4)
println((20 /: list)(minus))  // 10

// (1,2,3,4)(20)
println((list :\ 20 )(minus)) // 18

scan 扫描

描,即对某个集合的所有元素做 fold 操作,但是会产生的所有中间结果放置于一个集合中保存。

// 源码 scan
def scan[B >: A, That](z: B)(op: (B, B) => B)(implicit cbf: CanBuildFrom[Repr, B, That]): That = scanLeft(z)(op)

// 源码 scanLeft
def scanLeft[B, That](z: B)(op: (B, A) => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {
  val b = bf(repr)
  b.sizeHint(this, 1)
  var acc = z
  b += acc
  for (x <- this) { acc = op(acc, x); b += acc }
  b.result
}

// 源码 scanRight
def scanRight[B, That](z: B)(op: (A, B) => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {
  var scanned = List(z)
  var acc = z
  for (x <- reversed) {
    acc = op(x, acc)
    scanned ::= acc
  }
  val b = bf(repr)
  for (elem <- scanned) b += elem
  b.result
}
val list = List(1, 2, 3, 4, 5)
def minus(num1: Int, num2: Int): Int = {
  num1 - num2
}

// 5 (1, 2, 3, 4, 5) => (5, 4, 2, -1, -5, -10)
println(list.scan(5)(minus))

// 5 (1, 2, 3, 4, 5) => (5, 4, 2, -1, -5, -10)
println(list.scanLeft(5)(minus))

// (1, 2, 3, 4, 5) 5 => (-2, 3, -1, 4, 0, 5)
println(list.scanRight(5)(minus))

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值