san vs reduce

scanreduceCombine 框架中的两个操作符,它们都用于将多个输入值聚合为一个输出值,但它们之间有一些关键区别。下面将详细比较这两个操作符。

1. 输出频率

  • scan:

    • 在每个输入值被处理时都会输出当前的累积结果。

    • 适用于需要查看中间状态的场景。

  • reduce:

    • 只在源 Publisher 完成时输出最终结果。

    • 适用于只关心最终结果的场景。

2. 使用场景

  • scan:

    • 常用于实时计算和状态跟踪。

    • 适合需要逐步输出结果的情况,如累积和、计数等。

    • 例如,监控用户的点击次数并实时输出。

  • reduce:

    • 常用于数据聚合,尤其是在需要最终结果的场景。

    • 适合对一组数据进行汇总或聚合,如求和、求平均值等。

    • 例如,计算一系列数值的总和,并只输出最终结果。

3. 累积结果的更新方式

  • scan:

    • 会在每次接收到新输入时,基于当前的累积结果和新输入来生成新的结果。

    • 允许在流处理过程中动态变化并返回中间结果。

  • reduce:

    • 在处理完所有输入后,返回一个最终的累积结果。

    • 无法提供中间结果,适合在处理结束后的一次性结果。

4. 初始值的使用

  • scan:

    • 可以使用初始值来开始累积,并在后续每次输入时更新该值。

  • reduce:

    • 同样可以接受初始值,但最终结果只在所有输入都处理完毕后返回。

示例比较

以下是 scanreduce 的示例,演示它们在处理相同数据流时的不同表现。

使用 scan 的示例

import Combine

let numbers = [1, 2, 3, 4, 5].publisher

let scanSubscription = numbers
    .scan(0) { (currentSum, number) in
        currentSum + number
    }
    .sink { cumulativeSum in
        print("Cumulative sum (scan): \(cumulativeSum)")
    }

// 输出:
// Cumulative sum (scan): 1
// Cumulative sum (scan): 3
// Cumulative sum (scan): 6
// Cumulative sum (scan): 10
// Cumulative sum (scan): 15

使用 reduce 的示例

import Combine

let numbers = [1, 2, 3, 4, 5].publisher

let reduceSubscription = numbers
    .reduce(0) { (currentSum, number) in
        currentSum + number
    }
    .sink { total in
        print("Total sum (reduce): \(total)")
    }

// 输出: Total sum (reduce): 15

特性

scan

reduce

输出频率

每个输入值处理后都输出当前的累积结果

只在所有输入处理完成后输出最终结果

使用场景

实时计算和状态跟踪,例如计数、累加等

数据聚合,例如求和、求平均值

累积结果更新

动态变化并返回中间结果

无法提供中间结果,返回最终累积结果

初始值

可使用初始值开始累积

可接受初始值,但只返回最终结果

适合的操作

适合需要实时查看中间结果的场景

适合只关心最终结果的场景

示例输出

输出每步的累积和,如 1, 3, 6, 10, 15

仅输出最终总和,如 15

总结

  • scan 适合于需要实时查看中间结果的场景,它允许在数据流的每一步输出累积状态。

  • reduce 更加关注最终结果,适合用于数据汇总和聚合,只在所有输入处理完毕后返回结果。

  • 选择使用哪一个操作符,主要取决于你对数据流处理的需求:是否需要实时更新和中间结果,或仅关心最终输出。

Last updated