Repository: ReactiveX/RxSwift
File: RxSwift/Traits/Single.swift (Swift)

Code before:
            return Single(raw: primitiveSequence.source.map(transform))
    }
    
    /**
     Projects each element of an observable sequence to an observable sequence and merges the resulting observable sequences into one observable sequence.
     
     - seealso: [flatMap operator on reactivex.io](http://reactivex.io/documentation/operators/flatmap.html)
     
     - parameter selector: A transform function to apply to each element.
     - returns: An observable sequence whose elements are the result of invoking the one-to-many transform function on each element of the input sequence.
     */
    public func flatMap<R>(_ selector: @escaping (ElementType) throws -> Single<R>)
        -> Single<R> {
            return Single<R>(raw: primitiveSequence.source.flatMap(selector))
    }
    
    /**
     Merges the specified observable sequences into one observable sequence by using the selector function whenever all of the observable sequences have produced an element at a corresponding index.
     
     - parameter resultSelector: Function to invoke for each series of elements at corresponding indexes in the sources.
     - returns: An observable sequence containing the result of combining elements of the sources using the specified result selector function.
     */
    public static func zip<C: Collection, R>(_ collection: C, _ resultSelector: @escaping ([ElementType]) throws -> R) -> PrimitiveSequence<TraitType, R> where C.Iterator.Element == PrimitiveSequence<TraitType, ElementType> {
        
        if collection.isEmpty {
            return PrimitiveSequence<TraitType, R>(raw: .just(try! resultSelector([])))
        }
        
        let raw = Observable.zip(collection.map { $0.asObservable() }, resultSelector)
        return PrimitiveSequence<TraitType, R>(raw: raw)
    }
    
    /**
     Merges the specified observable sequences into one observable sequence all of the observable sequences have produced an element at a corresponding index.
     
     - returns: An observable sequence containing the result of combining elements of the sources.
     */
    public static func zip<C: Collection>(_ collection: C) -> PrimitiveSequence<TraitType, [ElementType]> where C.Iterator.Element == PrimitiveSequence<TraitType, ElementType> {
        
        if collection.isEmpty {
            return PrimitiveSequence<TraitType, [ElementType]>(raw: .just([]))
        }
        
        let raw = Observable.zip(collection.map { $0.asObservable() })
        return PrimitiveSequence(raw: raw)
    }
}


Review comment (suggestion):
We can't use `try!`.

We should probably do something as this.

```
return PrimitiveSequence<TraitType, R>.defer {
     return PrimitiveSequence<TraitType, R>(raw: .just(try resultSelector([])))
}
```

and add a test case for that.

Defer is here to make sure `resultSelector ` is being called once per subscription and not per zip invocation. This shouldn't have much difference, but if somebody decides to do a dirty hack and perform side effects inside `resultSelector`, version with `defer` will work with `retry` operators nicely.

Code after:
            return Single(raw: primitiveSequence.source.map(transform))
    }
    
    /**
     Projects each element of an observable sequence to an observable sequence and merges the resulting observable sequences into one observable sequence.
     
     - seealso: [flatMap operator on reactivex.io](http://reactivex.io/documentation/operators/flatmap.html)
     
     - parameter selector: A transform function to apply to each element.
     - returns: An observable sequence whose elements are the result of invoking the one-to-many transform function on each element of the input sequence.
     */
    public func flatMap<R>(_ selector: @escaping (ElementType) throws -> Single<R>)
        -> Single<R> {
            return Single<R>(raw: primitiveSequence.source.flatMap(selector))
    }
    
    /**
     Merges the specified observable sequences into one observable sequence by using the selector function whenever all of the observable sequences have produced an element at a corresponding index.
     
     - parameter resultSelector: Function to invoke for each series of elements at corresponding indexes in the sources.
     - returns: An observable sequence containing the result of combining elements of the sources using the specified result selector function.
     */
    public static func zip<C: Collection, R>(_ collection: C, _ resultSelector: @escaping ([ElementType]) throws -> R) -> PrimitiveSequence<TraitType, R> where C.Iterator.Element == PrimitiveSequence<TraitType, ElementType> {
        
        if collection.isEmpty {
            return PrimitiveSequence<TraitType, R>.deferred {
                return PrimitiveSequence<TraitType, R>(raw: .just(try resultSelector([])))
            }
        }
        
        let raw = Observable.zip(collection.map { $0.asObservable() }, resultSelector)
        return PrimitiveSequence<TraitType, R>(raw: raw)
    }
    
    /**
     Merges the specified observable sequences into one observable sequence all of the observable sequences have produced an element at a corresponding index.
     
     - returns: An observable sequence containing the result of combining elements of the sources.
     */
    public static func zip<C: Collection>(_ collection: C) -> PrimitiveSequence<TraitType, [ElementType]> where C.Iterator.Element == PrimitiveSequence<TraitType, ElementType> {
        
        if collection.isEmpty {
            return PrimitiveSequence<TraitType, [ElementType]>(raw: .just([]))
        }
        
        let raw = Observable.zip(collection.map { $0.asObservable() })
        return PrimitiveSequence(raw: raw)
    }
}