首页 > 解决方案 > Swift Combine:使用类似滑动窗口的功能进行收集

问题描述

所以我有这个联合发布者说发出整数 - 1,2,3,4,5,6,7,8,9,10,11 ....

这些整数虽然并不总是存在。它们是即时生成的并发送给发布者。

我知道收集运算符,当说它被称为 .collect(5) 给我 -[1,2,3,4,5], [6,7,8,9,10], ...

相反,我正在寻找的有点像 buffer 和 collect 组合 - [1,2,3,4,5], [2,3,4,5,6], [3,4,5,6,7] ...

有没有办法在不编写自定义运算符的情况下做到这一点?如果自定义运算符是要走的路,你能提供一些指导吗,我以前没有写过自定义运算符。我希望我所要求的可以从示例中清楚地看出。

谢谢

编辑

这可行,但我不确定这是否是最好的解决方案 -

publisher.zip(
    publisher.dropFirst(),
    publisher.dropFirst(2))

标签: swiftcombine

解决方案


您可以使用scan运算符来实现此效果。Scan使您能够累积一个值 - 在这种情况下是一个先前值的数组 - 然后发出它。您只需要删除最初的 N-1 个较小的数组。

为方便起见,您可以创建自定义运算符sliding(window:)

extension Publisher {
    func sliding(window: Int) -> AnyPublisher<[Output], Failure> {
        if window < 1 { return Empty().eraseToAnyPublisher() }
        return self
           .scan([], { arr, value in
               if arr.count < window {
                   return arr + [value]
               } else {
                   return arr.dropFirst() + [value]
               }
           })
           .dropFirst(window - 1)
           .eraseToAnyPublisher()
   }
}

用法是:

[1,2,3,4,5,6,7,8,9,10].publisher
   .sliding(window: 5)
   .sink { print($0) }

输出将是:

[1, 2, 3, 4, 5]
[2, 3, 4, 5, 6]
[3, 4, 5, 6, 7]
[4, 5, 6, 7, 8]
[5, 6, 7, 8, 9]
[6, 7, 8, 9, 10]

推荐阅读