I have two deferred publishers emitting an array of Ints. They are Futures under the hood of that maters.
I would like to have these two publishers "run" in parallel so lets say p1
returns [1, 2, 3]
and p2
[4, 5, 6]
I would like to be able to get [4, 5, 6, 1, 2, 3]
or [1, 2, 3, 4, 5, 6]
Here is my code making an attempt
let p1: AnyPublisher<[Int], Never>
let p2: AnyPublisher<[Int], Never>
let combined: AnyPublisher<[Int], Never> = Publishers.MergeMany([p1, p2])
.collect()
.eraseToAnyPublisher()
This gives me the error Type of expression is ambiguous without a type annotation
Notably the type after collect()
is of type Publishers.Collect<Publishers.MergeMany<AnyPublisher<[Int], Never>>>
so I figured I could just erase it to be any publisher.
As near as I can tell collect does what I want. But since I want to get out the publisher and not sink I am not sure how to get around this.
I also tried
var res: AnyPublisher<[Reminder], Never>
Publishers.MergeMany([singleReminderPublisher(), singleReminderPublisher(), singleReminderPublisher()])
.collect()
.assign(to: &res)
return res
but that gives me Cannot convert value of type 'AnyPublisher<[Reminder], Never>' to expected argument type 'Published<[AnyPublisher<[Reminder], Never>.Output]>.Publisher'
. This is certainly a more useful error message but I still don't know what to do with it.
Edit: Thanks to @Joakim's comment about trying to get Publisher<[[Int]], Never>
I was inspired with one solution
Publishers.Zip3(p1, p2, p3)
.map( { r1, r2, r3 in
var combine: [Int] = []
combine.append(contentsOf: r1)
combine.append(contentsOf: r2)
combine.append(contentsOf: r3)
return combine
})
.eraseToAnyPublisher()
The major downside of this to me is that it is not agnostic to the number of publishers and there's extra storage use that could matter if these objects were larger or there were more of them. I would also love to understand why .collect().eraseToAnyPublisher()
did not work still.
Keep in mind that Publisher<T, Never>
are supposed to publish any number of T
s. The number of elements that the MergeMany
publisher will publish is the sum of all the elements that p1
and p2
will publish.
Since p1
and p2
are Future
s, they will each publish one Int
array, so MergeMany
will publish two Int
arrays. You then collect
this, converting the publisher that would publish two Int
arrays, into a publisher that will only publish both Int
arrays as one element. That one element is of type [[Int]]
, because the two Int
arrays are put into another array.
Your desired result is the concatenation of the two arrays that p1
and p2
publish, so the natural thing to do is to flatten it with a map
.
let combined: AnyPublisher<[Int], Never> = Publishers.MergeMany([p1, p2])
.collect()
.map { x in x.flatMap { $0 } }
.eraseToAnyPublisher()
Alternatively (IMO this looks better), you can flatMap
the publisher that produces 2 Int
arrays, into a publisher that produces Int
s, then collect
this Int
publisher.
let combined: AnyPublisher<[Int], Never> = Publishers.MergeMany([p1, p2])
.flatMap { $0.publisher }
.collect()
.eraseToAnyPublisher()