kotlin的高阶函数:Reduce() ReduceRight()
val s = listOf<String>("1", "2", "3")
println(s.reduce { acc, s -> s + acc })
println(s.reduce { acc, s -> acc + s })
println(s.reduceRight { s, acc -> s + acc })
println(s.reduceRight { s, acc -> acc + s })
如上的输出你能准确说出吗?
321
123
123
321
其中2和4是正确的使用姿势,虽然1和3是错误的姿势,但同样可以实现效果
下面看源码分析:
public inline fun <S, T : S> Iterable<T>.reduce(operation: (acc: S, T) -> S): S {
//累计因子acc,值为第一个元素的值。累计时从第二个元素开始
val iterator = this.iterator()
if (!iterator.hasNext()) throw UnsupportedOperationException("Empty collection can't be reduced.")
var accumulator: S = iterator.next()
while (iterator.hasNext()) {
//这里是重点,按照传入的operation的进行操作,函数作为参数传入
accumulator = operation(accumulator, iterator.next())
}
return accumulator
}
这里最重要的就是operation对应的就是acc + s -> s + acc,也就是s和acc顺序写反导致结果相反的原因
比如[1, 2, 3]:
第一轮:acc = 1 s = 2 -> acc = 21 s = 2
第二轮:acc = 21 s = 3 -> acc = 321 s = 3
最终得到了321
同样的reduceRight也是一样的,reduceRight是累计因子取最后一个值,往前遍历
listIterator(size)
原理就是这样,如果还感觉绕,可以把源码粘出来,直接自行断点/log调试,一目了然
fold() foldRight()原理一样,只是多了一个初始值,再累计