在常用的高阶函数中,相比于 map、flatMap、filter 这些,reduce 理解起来更晦涩一些,不如前面几个功能明确。
reduce 一词,在英文中的解释为“减少、降低等”,在函数式编程中,我们可以把这个单词理解为“合并、归纳”。也就是说,reduce 的作用是合并结果,把多项变成一项。至于怎么合并,就看传入的转换方法是什么。
部分编程语言也会使用 fold、compress 等表示 reduce ,参考 https://en.wikipedia.org/wiki/Fold_%28higher-order_function%29 。但是主流编程语言中,还是使用 reduce 一词的比较多。
Swift中的 reduce
Swift提供了两个不同的 reduce 方法。
reduce(_:_:)
1 | /// Returns the result of combining the elements of the sequence using the given closure. |
reduce(into:_:)
1 | /// Returns the result of combining the elements of the sequence using the given closure. |
两个方法的作用完全一样,都是 Returns the result of combining the elements of the sequence using the given closure ,翻译过来就是 使用传入的closure合并序列并返回 。在使用上两个方法有什么区别呢?
TLDR: 具体作用没区别。只是当返回结果为
Array
、Dictionary
等 Coy On Write 类型的数据时,优先使用reduce(into:_:)
以提升性能。
reduce(_:_:)
1 | /// - Parameters: |
以下面的代码为例,介绍reduce(_:_:)
的执行流程。
1 | let numbers = [1, 2, 3, 4] |
- 调用 nextPartialResult,传入的参数为
x
: *initialResult(0
),y
:*numbers 数组第一个元素(1
),返回相加的结果:1
。 - 继续调用 nextPartialResult,传入的参数为
x
: 上一步的返回值,y
:numbers 数组下一个元素,返回相加的结果。 - numbers 数组遍历完毕后,将最后的结果最为返回值返回。
如果 numbers 数组为空,则 nextPartialResult 不会执行,直接返回 initialResult。
reduce(into:_:)
1 | /// - Parameters: |
以下面的代码为例,介绍reduce(into:_:)
的执行流程。
1 | let letters = "abracadabra" |
- 调用 updateAccumulatingResult,传入的参数为
counts
: *initialResult([:]
),letter
: *letters 数组第一个元素(a
),返回结果:[a: 1]
。 - 继续调用 updateAccumulatingResult ,传入的参数为
counts
: 上一步的返回值,letter
: letters 数组下一个元素,返回结果。 - letters 数组遍历完毕后,将最后的结果最为返回值返回。
如果 letters 数组为空,则 updateAccumulatingResult 不会执行,直接返回 initialResult 。
总结
reduce(_:_:)
和 reduce(into:_:)
除了参数不一样外真没啥区别。不过从方法命名上看,我们也能大概猜到 reduce(into:_:)
会把归并结果会更新到 initialResult ,这应该就是Swift官方推荐当返回结果为Array
、Dictionary
等 Coy On Write 类型的数据时,优先使用reduce(into:_:)
的原因。
This method(
reduce(into:_:)
) is preferred overreduce(_:_:)
for efficiency when the result is a copy-on-write type, for example an Array or a Dictionary.
使用reduce实现map、filter等
弄明白 reduce 的原理之后,大家可以发现这是一个很灵活的方法。基本上能用 map、filter 实现的功能都可以用 reduce 代替。
使用reduce实现map
1 | extension Array { |
使用reduce实现filter
1 | extension Array { |