I have been using Apple\'s native zip(_:_:)
recently and I ran into a situation whereby I needed
You need all the functions but you don't need multiple ZipSequence types.
@inlinable public func zip<Sequence0: Sequence, Sequence1: Sequence, Sequence2: Sequence>(
_ sequence0: Sequence0, _ sequence1: Sequence1, _ sequence2: Sequence2
) -> AnySequence<(Sequence0.Element, Sequence1.Element, Sequence2.Element)> {
.init(
sequence(
state: (
sequence0.makeIterator(), sequence1.makeIterator(), sequence2.makeIterator()
)
) {
.init(
($0.0.next(), $0.1.next(), $0.2.next())
)
}
)
}
@inlinable public func zip<
Sequence0: Sequence, Sequence1: Sequence, Sequence2: Sequence, Sequence3: Sequence
>(
_ sequence0: Sequence0, _ sequence1: Sequence1, _ sequence2: Sequence2, _ sequence3: Sequence3
) -> AnySequence<(Sequence0.Element, Sequence1.Element, Sequence2.Element, Sequence3.Element)> {
.init(
sequence(
state: (
sequence0.makeIterator(), sequence1.makeIterator(), sequence2.makeIterator(), sequence3.makeIterator()
)
) {
.init(
($0.0.next(), $0.1.next(), $0.2.next(), $0.3.next())
)
}
)
}
public extension Optional {
/// Exchange three optionals for a single optional tuple.
/// - Returns: `nil` if any tuple element is `nil`.
init<Wrapped0, Wrapped1, Wrapped2>(_ optionals: (Wrapped0?, Wrapped1?, Wrapped2?))
where Wrapped == (Wrapped0, Wrapped1, Wrapped2) {
switch optionals {
case let (wrapped0?, wrapped1?, wrapped2?):
self = (wrapped0, wrapped1, wrapped2)
default:
self = nil
}
}
/// Exchange four optionals for a single optional tuple.
/// - Returns: `nil` if any tuple element is `nil`.
init<Wrapped0, Wrapped1, Wrapped2, Wrapped3>(_ optionals: (Wrapped0?, Wrapped1?, Wrapped2?, Wrapped3?))
where Wrapped == (Wrapped0, Wrapped1, Wrapped2, Wrapped3) {
switch optionals {
case let (wrapped0?, wrapped1?, wrapped2?, wrapped3?):
self = (wrapped0, wrapped1, wrapped2, wrapped3)
default:
self = nil
}
}
}
Sadly, this is not completely possible in Swift since we can't have different Array types for Variadic parameters. A possible work around would be to convert all arrays to type [Any]
, and then zip them all together which forms an array array, and than using map
, converting the arrays to the wanted tuple using force casting. The solution might be bit dirty but not all too complicated.
extension Sequence {
//easy conversion of any sequence to [Any]
var untyped:[Any] {
return self as! [Any]
}
}
func zip(_ untypedSequences:[Any]...) -> [[Any]] {
let count = untypedSequences.map{$0.count}.min() ?? 0
return (0..<count).map{ index in untypedSequences.map{ $0[index] } }
}
//Test
let test1 = ["a", "b", "c"]
let test2 = [1, 2, 3, 4]
let test3 = [7.2, 12.23, 1.3]
let zippedTests = zip(test1.untyped, test2.untyped, test3.untyped).map {
($0[0] as! String, $0[1] as! Int, $0[2] as! Double)
}