Skip to content

Instantly share code, notes, and snippets.

@kristopherjohnson
Last active December 10, 2022 14:21
Show Gist options
  • Save kristopherjohnson/04dbc470e17f67f836a2 to your computer and use it in GitHub Desktop.
Save kristopherjohnson/04dbc470e17f67f836a2 to your computer and use it in GitHub Desktop.
zip(), zip3(), unzip(), and unzip3() for Swift
// Given array of 2-tuples, return two arrays
func unzip<T, U>(array: [(T, U)]) -> ([T], [U]) {
var t = Array<T>()
var u = Array<U>()
for (a, b) in array {
t.append(a)
u.append(b)
}
return (t, u)
}
// Given sequence of 2-tuples, return two arrays
func unzip<T, U>(sequence: SequenceOf<(T, U)>) -> ([T], [U]) {
var t = Array<T>()
var u = Array<U>()
for (a, b) in sequence {
t.append(a)
u.append(b)
}
return (t, u)
}
// Given array of 3-tuples, return three arrays
func unzip3<T, U, V>(array: [(T, U, V)]) -> ([T], [U], [V]) {
var t = Array<T>()
var u = Array<U>()
var v = Array<V>()
for (a, b, c) in array {
t.append(a)
u.append(b)
v.append(c)
}
return (t, u, v)
}
// Given sequence of 3-tuples, return three arrays
func unzip3<T, U, V>(sequence: SequenceOf<(T, U, V)>) -> ([T], [U], [V]) {
var t = Array<T>()
var u = Array<U>()
var v = Array<V>()
for (a, b, c) in sequence {
t.append(a)
u.append(b)
v.append(c)
}
return (t, u, v)
}
let elements = [(0, "Zero"), (1, "One"), (2, "Two")]
let (numbers, strings) = unzip(elements)
println("numbers = \(numbers)")
println("strings = \(strings)")
// numbers = [0, 1, 2]
// strings = ["Zero", "One", "Two]
let elements3 = [(0, "Zero", "A"), (1, "One", "B"), (2, "Two", "C")]
let (numbers3, strings3, letters3) = unzip3(elements3)
println("numbers3 = \(numbers3)")
println("strings3 = \(strings3)")
println("letters3 = \(letters3)")
// numbers3 = [0, 1, 2]
// strings3 = ["Zero", "One", "Two]
// letters3 = ["A", "B", "C"]
// zip
// Given two sequences, return a sequence of 2-tuples (pairs)
public func zip<A: SequenceType, B: SequenceType>(a: A, b: B)
-> ZipSequence<A, B>
{
return ZipSequence(a, b)
}
// Lazy sequence of tuples created from values from two other sequences
public struct ZipSequence<A: SequenceType, B: SequenceType>: SequenceType {
private var a: A
private var b: B
public init (_ a: A, _ b: B) {
self.a = a
self.b = b
}
public func generate() -> ZipGenerator<A.Generator, B.Generator> {
return ZipGenerator(a.generate(), b.generate())
}
}
// Generator that creates tuples of values from two other generators
public struct ZipGenerator<A: GeneratorType, B: GeneratorType>: GeneratorType {
private var a: A
private var b: B
public init(_ a: A, _ b: B) {
self.a = a
self.b = b
}
mutating public func next() -> (A.Element, B.Element)? {
switch (a.next(), b.next()) {
case let (.Some(aValue), .Some(bValue)):
return (aValue, bValue)
default:
return nil
}
}
}
// zip3
// Given three sequences, return a sequence of 3-tuples
public func zip3<A: SequenceType, B: SequenceType, C: SequenceType>(a: A, b: B, c: C)
-> ZipSequence3<A, B, C>
{
return ZipSequence3(a, b, c)
}
// Sequence of tuples created from values from three other sequences
public struct ZipSequence3<A: SequenceType, B: SequenceType, C: SequenceType>: SequenceType {
private var a: A
private var b: B
private var c: C
public init (_ a: A, _ b: B, _ c: C) {
self.a = a
self.b = b
self.c = c
}
public func generate() -> ZipGenerator3<A.Generator, B.Generator, C.Generator> {
return ZipGenerator3(a.generate(), b.generate(), c.generate())
}
}
// Generator that creates tuples of values from three other generators
public struct ZipGenerator3<A: GeneratorType, B: GeneratorType, C: GeneratorType>: GeneratorType {
private var a: A
private var b: B
private var c: C
public init(_ a: A, _ b: B, _ c: C) {
self.a = a
self.b = b
self.c = c
}
mutating public func next() -> (A.Element, B.Element, C.Element)? {
switch (a.next(), b.next(), c.next()) {
case let (.Some(aValue), .Some(bValue), .Some(cValue)):
return (aValue, bValue, cValue)
default:
return nil
}
}
}
// Examples
let numbers = [0, 1, 2, 3, 4]
let names = ["Zero", "One", "Two", "Three"]
let letters = ["A", "B", "C"]
let result = zip(numbers, names)
let printableResult = ", ".join(map(result) { "(\($0.0), \($0.1))" })
println("result: \(printableResult)")
// result: (0, Zero), (1, One), (2, Two), (3, Three)
let result3 = zip3(numbers, names, letters)
let printableResult3 = ", ".join(map(result3) { "(\($0.0), \($0.1), \($0.2))" })
println("result3: \(printableResult3)")
// result3: (0, Zero, A), (1, One, B), (2, Two, C)
let resultOne = filter(result3) { $0.1 == "One" }
let printableResultOne = ", ".join(resultOne.map { "(\($0.0), \($0.1), \($0.2))" })
println("resultOne: \(printableResultOne)")
// resultOne: (1, One, B)
// Note: Standard Swift Library provides Zip2, which is a struct
// but we can use it almost like a function.
let zip2Result = Zip2(numbers, names)
let printableZip2Result = ", ".join(map(zip2Result) { "(\($0.0), \($0.1))" })
println("zip2Result: \(printableZip2Result)")
// result: (0, Zero), (1, One), (2, Two), (3, Three)
@kristopherjohnson
Copy link
Author

For unzip/unzip3, I provide functions that take either an array or a SequenceOf. I couldn't figure out how to declare a function that just takes a Sequence where GeneratorType.Element is a tuple. Can someone help?

@kristopherjohnson
Copy link
Author

@airspeedswift posted a blog entry inspired by these definitions: http://airspeedvelocity.net/2014/08/02/tuple-wrangling/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment