swift 快速合并:如何在收集的同时保持发布者结果的顺序?

13z8s7eq  于 2023-01-20  发布在  Swift
关注(0)|答案(1)|浏览(209)

我有一组发布者,我希望等待所有发布者都发布了值,然后处理结果。
我尝试将collect()Publishers.MergeMany一起使用(编辑:使用MergeMany,因为我正在寻找一个可以扩展到40个或更多发布者的解决方案),但是collect只是按照接收的顺序收集结果,而没有考虑值的顺序,以便正确地关联发布者和值。
为了简化代码并说明问题,下面是Playground代码:

import Combine

var cancellables = [AnyCancellable]()

let stringPublishers = [
    Just("1").delay(for: RunLoop.SchedulerTimeType.Stride(Double.random(in: 0.1...1.0)), scheduler: RunLoop.main),
    Just("2").delay(for: RunLoop.SchedulerTimeType.Stride(Double.random(in: 0.1...1.0)), scheduler: RunLoop.main),
    Just("3").delay(for: RunLoop.SchedulerTimeType.Stride(Double.random(in: 0.1...1.0)), scheduler: RunLoop.main),
    Just("4").delay(for: RunLoop.SchedulerTimeType.Stride(Double.random(in: 0.1...1.0)), scheduler: RunLoop.main),
    Just("5").delay(for: RunLoop.SchedulerTimeType.Stride(Double.random(in: 0.1...1.0)), scheduler: RunLoop.main)
]

Publishers.MergeMany(stringPublishers).collect().sink { value in
    print(value)
}.store(in: &cancellables)

运行代码,结果通常是无序的,如["2", "4", "5", "3", "1"]["1", "4", "5", "3", "2"],等等。我怎么总是得到["1", "2", "3", "4", "5"]
我试着在这里修改solution,但是遇到了麻烦,因为我的inputArray已经是Publishers的数组,而不是整数或字符串的普通值。

fkaflof6

fkaflof61#

下面是一个函数,它将接受任意数量的发布者,并将它们组合成一个发布者,该发布者包含一个遵守顺序的元素数组:

func combineLatest<Pub>(_ pubs: [Pub]) -> AnyPublisher<[Pub.Output], Pub.Failure> where Pub: Publisher {
    guard !pubs.isEmpty else { return Empty().eraseToAnyPublisher() }
    return pubs.dropFirst().reduce(pubs[0].map { [$0] }.eraseToAnyPublisher()) { partial, next in
        partial.combineLatest(next)
            .map { $0 + [$1] }
            .eraseToAnyPublisher()
    }
}

它可以像这样使用:

combineLatest(stringPublishers).sink(receiveValue: {
    print($0)
})
.store(in: &cancellables)

如果你不喜欢自由函数,你可以把它放在扩展中:

extension Collection where Element: Publisher {
    func combineLatest() -> AnyPublisher<[Element.Output], Element.Failure> {
        guard !isEmpty else { return Empty().eraseToAnyPublisher() }
        return dropFirst().reduce(first!.map { [$0] }.eraseToAnyPublisher()) { partial, next in
            partial.combineLatest(next)
                .map { $0 + [$1] }
                .eraseToAnyPublisher()
        }
    }
}

相关问题