You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift Combine:如何收集结果时保留发布者的输出顺序?

解决Combine中MergeMany收集结果保留原始顺序的问题

核心思路

Publishers.MergeMany是按发布者完成顺序输出值,而我们需要对应原始数组的位置顺序。解决关键是给每个发布者的结果绑定它在原数组中的索引,收集后按索引排序再提取值。

实现代码

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)
]

// 给每个发布者绑定索引,将结果包装成(索引, 值)的元组
let indexedPublishers = stringPublishers.enumerated().map { index, publisher in
    publisher.map { (index, $0) }
}

// 合并带索引的发布者,收集后按索引排序并提取最终值
Publishers.MergeMany(indexedPublishers)
    .collect()
    .map { tuples in
        tuples.sorted(by: { $0.0 < $1.0 }).map { $0.1 }
    }
    .sink { value in
        print(value) // 始终输出 ["1", "2", "3", "4", "5"]
    }
    .store(in: &cancellables)

代码说明

  • 绑定索引:用enumerated()遍历原发布者数组,给每个发布者的结果添加它在原数组中的位置索引,让每个值都能追溯到原始位置。
  • 排序提取:收集所有带索引的元组后,先按索引从小到大排序,再提取元组中的值,就能得到和原发布者数组顺序完全一致的结果。
  • 兼容性:该方案完全支持40个及以上的发布者,MergeMany和后续排序操作不会因数量过多出现异常(只要内存能容纳所有结果)。

内容的提问来源于stack exchange,提问作者Rodolfo Romero

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 21:20:40