Let's assume a function is called when mapping an array, and this function returns a Result. For example:
func parseFeedItem(_ object: Any) -> Result<FeedItem, Error> {...}
func parseFeed(_ root: Any) -> Result<Feed, Error> {
...
let items = objects.compactMap { parseFeedItem($0) }
...
}
The result of the map (items above), will be an array of Results. Ideally, following this, we'd want to know the "union" of results, that is a Result as either:
successwith an array of values, if allResults in the array aresuccesses; orfailurewith the error of the firstfailurein the array.
Basically, I came up with:
typealias Results<T, E> = Result<[T], E> where E: Error
let r: Results<FeedItem, Error> = items.reduce(.success([FeedItem]())) { (accumulator, result) -> Results<FeedItem, Error> in
switch accumulator {
case .failure(_):
return accumulator
case .success(let array):
switch result {
case .failure(let error):
return .failure(error)
case .success(let value):
var newArray = array
newArray.append(value)
return .success(newArray)
}
}
}
For example, if run with only successes:
let items: [Result<FeedItem, Error>] = [
.success(FeedItem(1)),
.success(FeedItem(2)),
.success(FeedItem(3)),
]
... run `reduce` defined above ...
print(r) // .success([FeedItem(1), FeedItem(2), FeedItem(3)])
And if the array contains at least one failure, like:
let items: [Result<FeedItem, Error>] = [
.success(FeedItem(1)),
.success(FeedItem(2)),
.failure(MyError.blah),
]
... run `reduce` defined above ...
print(r) // .failure(MyError.blah)
So this works. However, here are the questions:
- is there a shorter way to do this?
- is it performant, i.e. is there any way this could be improved?