我正在寻找一个与collect运算符相反的运算符:
- 允许您从一个发射值映射到多个发射值,在流上发射它们。例如,如果流中有元素
[1,2,3]
,我想将其转换为一个先发出1
,然后发出2
,再发出3
的流 - 不会更改流的完成状态。诚然,该
uncollect
运算符不会与collect
完全相反,因为collect
等待直到流结束。对于uncollect
,它应该只在流未完成时处理结果,而不是尝试完成/取消完成流
例如,我认为uncollect
运算符的作用如下:
func fibonacci(_ number: Int) -> AnyPublisher<Int, Never> {
Future { ... }.eraseToAnyPublisher()
}
let serverEventStream: AnyPublisher<[Int], Never> = ...
serverEventStream // AnyPublisher<[Int], Never> // Ex. 2 values: `[12, 24]`, `[1, 10, 50]`
.uncollect { $0 } // AnyPublisher<Int, Never> // Ex. 5 values: `12`, `24`, `1`, `10`, `50`
.flatMap { fibonacci($0) } // AnyPublisher<Int, Never> // Ex. 5 values: `144`, `46368`, `1`, `55`, `12586269025`
.sink { print($0) }
我一直在寻找像explode
、splat
或uncollect
这样的名字,但都无济于事。共享一个有前途的名称的最接近的运算符是flatMap
,因为Sequence.flatMap
在非Combine世界中是等价的。然而,Combine的flatMap
是将承诺链接在一起的方式。
有没有一种方法可以取消元素的选择,或者将单个排放映射为任意数量的排放?
我能够让它与我的自定义JustSeveral
发布服务器一起工作,但这似乎很笨拙:
class Tests: XCTestCase {
func testUncollect() {
func fibonacci(_ number: Int) -> AnyPublisher<Int, Never> {
switch number {
case 1: return Just(1).eraseToAnyPublisher()
case 10: return Just(55).eraseToAnyPublisher()
case 12: return Just(144).eraseToAnyPublisher()
case 24: return Just(46368).eraseToAnyPublisher()
case 50: return Just(12586269025).eraseToAnyPublisher()
default: fatalError("Should actually build this function.")
}
}
let serverEventStream: AnyPublisher<[Int], Never> = JustSeveral([[12, 24], [1, 10, 50]]).eraseToAnyPublisher()
serverEventStream // AnyPublisher<[Int], Never> // Ex. 2 values: `[12, 24]`, `[1, 10, 50]`
.uncollect { $0 } // AnyPublisher<Int, Never> // Ex. 5 values: `12`, `24`, `1`, `10`, `50`
.flatMap { fibonacci($0) } // AnyPublisher<Int, Never> // Ex. 5 values: `144`, `46368`, `1`, `55`, `12586269025`
.sink { print($0) }
}
}
extension Publisher {
func uncollect<T>(_ transform: @escaping (Output) -> [T]) -> AnyPublisher<T, Failure> {
self
.flatMap { output -> AnyPublisher<T, Failure> in
JustSeveral(transform(output))
.setFailureType(to: Failure.self)
.eraseToAnyPublisher()
}
.eraseToAnyPublisher()
}
}
您可以将flatMap
与新的发布者一起使用
[1,2,3,4,5,6].publisher
.collect()
.flatMap { $0.publisher }
.sink { print($0) }
1
2
3
4
5
6