Skip to content

Commit

Permalink
Merge pull request #122 from dn-m/zip
Browse files Browse the repository at this point in the history
Add zip (to longest) and associated sequences
  • Loading branch information
jsbean authored Jul 24, 2018
2 parents e376e16 + 8253939 commit dc5dbd5
Show file tree
Hide file tree
Showing 3 changed files with 214 additions and 44 deletions.
66 changes: 22 additions & 44 deletions Sources/DataStructures/Zip3Sequence.swift
Original file line number Diff line number Diff line change
Expand Up @@ -193,64 +193,42 @@
///
/// Modified by James Bean.
///
public func zip <A,B,C> (_ a: A, _ b: B, _ c: C) -> Zip3Sequence<A,B,C> {
return Zip3Sequence(a,b,c)
public func zip <Sequence1,Sequence2,Sequence3> (
_ sequence1: Sequence1,
_ sequence2: Sequence2,
_ sequence3: Sequence3
) -> Zip3Sequence<Sequence1,Sequence2,Sequence3>
{
return Zip3Sequence(sequence1,sequence2,sequence3)
}

public struct Zip3Sequence <A: Sequence, B: Sequence, C: Sequence>: Sequence {

/// A type whose instances can produce the elements of this sequence, in order.
public typealias Iterator = Zip3Iterator<A.Iterator, B.Iterator, C.Iterator>
public struct Zip3Sequence <
Sequence1: Sequence,
Sequence2: Sequence,
Sequence3: Sequence
>: IteratorProtocol, Sequence
{

private let a: A
private let b: B
private let c: C
private var iterator1: Sequence1.Iterator
private var iterator2: Sequence2.Iterator
private var iterator3: Sequence3.Iterator

/// Creates an instance that makes pairs of elements from `sequence1` and
/// `sequence2`.
public init(_ a: A, _ b: B, _ c: C) {
(self.a, self.b, self.c) = (a, b, c)
}

/// Returns an iterator over the elements of this sequence.
public func makeIterator() -> Iterator {
return Iterator(
a.makeIterator(),
b.makeIterator(),
c.makeIterator())
}
}

public struct Zip3Iterator <A: IteratorProtocol, B: IteratorProtocol, C: IteratorProtocol>
: IteratorProtocol
{

/// The type of element returned by `next()`.
public typealias Element = (A.Element, B.Element, C.Element)

private var a: A
private var b: B
private var c: C

/// Creates an instance around a pair of underlying iterators.
internal init(_ a: A, _ b: B, _ c: C) {
(self.a, self.b, self.c) = (a, b, c)
public init(_ sequence1: Sequence1, _ sequence2: Sequence2, _ sequence3: Sequence3) {
self.iterator1 = sequence1.makeIterator()
self.iterator2 = sequence2.makeIterator()
self.iterator3 = sequence3.makeIterator()
}

/// Advances to the next element and returns it, or `nil` if no next element
/// exists.
///
/// Once `nil` has been returned, all subsequent calls return `nil`.
public mutating func next() -> Element? {

guard
let a = a.next(),
let b = b.next(),
let c = c.next()
else {
public mutating func next() -> (Sequence1.Element, Sequence2.Element, Sequence3.Element)? {
guard let a = iterator1.next(), let b = iterator2.next(), let c = iterator3.next() else {
return nil
}

return (a, b, c)
}
}
140 changes: 140 additions & 0 deletions Sources/DataStructures/ZipToLongest.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
//
// ZipToLongest.swift
// DataStructures
//
// Created by James Bean on 7/24/18.
//

/// - Returns: A `ZipToLongest2Sequence` for the two given sequences, using `fill1` and
/// `fill2` as default values if the other sequence is longer.
public func zip <Sequence1,Sequence2> (
_ sequence1: Sequence1,
_ sequence2: Sequence2,
fill1: Sequence1.Element,
fill2: Sequence2.Element
) -> ZipToLongest2Sequence<Sequence1,Sequence2>
{
return ZipToLongest2Sequence(sequence1, sequence2, fill1: fill1, fill2: fill2)
}

/// - Returns: A `ZipToLongest2Sequence` for the two given sequences, using `fill` and
/// `fill` as default values if the other sequence is longer.
public func zip <Sequence1,Sequence2> (
_ sequence1: Sequence1,
_ sequence2: Sequence2,
fill: Sequence1.Element
) -> ZipToLongest2Sequence<Sequence1,Sequence2>
where Sequence1.Element == Sequence2.Element
{
return zip(sequence1, sequence2, fill1: fill, fill2: fill)
}

/// - Returns: A `ZipToLongest3Sequence` for the three given sequences, using `firstFill`,
/// `secondFill`, and `thirdFill` as default values if the other sequences are longer.
public func zip <Sequence1,Sequence2,Sequence3> (
_ sequence1: Sequence1,
_ sequence2: Sequence2,
_ sequence3: Sequence3,
fill1: Sequence1.Element,
fill2: Sequence2.Element,
fill3: Sequence3.Element
) -> ZipToLongest3Sequence<Sequence1,Sequence2,Sequence3>
{
return ZipToLongest3Sequence(
sequence1,
sequence2,
sequence3,
fill1: fill1,
fill2: fill2,
fill3: fill3
)
}

/// - Returns: A `ZipToLongest3Sequence` for the three given sequences, using `fill` as a default
/// value if the other sequences are longer.
public func zip <Sequence1,Sequence2,Sequence3> (
_ sequence1: Sequence1,
_ sequence2: Sequence2,
_ sequence3: Sequence3,
fill: Sequence1.Element
) -> ZipToLongest3Sequence<Sequence1,Sequence2,Sequence3>
where Sequence1.Element == Sequence2.Element, Sequence2.Element == Sequence3.Element
{
return ZipToLongest3Sequence(
sequence1,
sequence2,
sequence3,
fill1: fill,
fill2: fill,
fill3: fill
)
}

/// Lazy sequence zipping two `Sequence` values together to the longest of the two sequences,
/// filling in the others with the given `fill1`, and `fill2` values.
public struct ZipToLongest2Sequence <Sequence1: Sequence, Sequence2: Sequence>
: IteratorProtocol, Sequence
{
private var iterator1: Sequence1.Iterator
private var iterator2: Sequence2.Iterator
private let fill1: Sequence1.Element
private let fill2: Sequence2.Element

init(
_ sequence1: Sequence1,
_ sequence2: Sequence2,
fill1: Sequence1.Element,
fill2: Sequence2.Element
)
{
self.iterator1 = sequence1.makeIterator()
self.iterator2 = sequence2.makeIterator()
self.fill1 = fill1
self.fill2 = fill2
}

public mutating func next() -> (Sequence1.Element, Sequence2.Element)? {
let firstValue = iterator1.next()
let secondValue = iterator2.next()
guard firstValue != nil || secondValue != nil else { return nil }
return (firstValue ?? fill1, secondValue ?? fill2)
}
}

/// Lazy sequence zipping three `Sequence` values together to the longest of the three sequences,
/// filling in the others with the given `fill1`, `fill2`, and `fill3` values.
public struct ZipToLongest3Sequence <Sequence1: Sequence, Sequence2: Sequence, Sequence3: Sequence>
: IteratorProtocol, Sequence
{
private var iterator1: Sequence1.Iterator
private var iterator2: Sequence2.Iterator
private var iterator3: Sequence3.Iterator
private let fill1: Sequence1.Element
private let fill2: Sequence2.Element
private let fill3: Sequence3.Element

init(
_ sequence1: Sequence1,
_ sequence2: Sequence2,
_ sequence3: Sequence3,
fill1: Sequence1.Element,
fill2: Sequence2.Element,
fill3: Sequence3.Element
)
{
self.iterator1 = sequence1.makeIterator()
self.iterator2 = sequence2.makeIterator()
self.iterator3 = sequence3.makeIterator()
self.fill1 = fill1
self.fill2 = fill2
self.fill3 = fill3
}

public mutating func next() -> (Sequence1.Element, Sequence2.Element, Sequence3.Element)? {
let value1 = iterator1.next()
let value2 = iterator2.next()
let value3 = iterator3.next()
guard value1 != nil || value2 != nil || value3 != nil else { return nil }
return (value1 ?? fill1, value2 ?? fill2, value3 ?? fill3)
}
}
52 changes: 52 additions & 0 deletions Tests/DataStructuresTests/ZipToLongestTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//
// ZipToLongestTests.swift
// DataStructuresTests
//
// Created by James Bean on 7/24/18.
//

import XCTest
import DataStructures

class ZipToLongestTests: XCTestCase {

func testEqualLengths() {
let zipped = zip([1,4,7], [2,5,8], [3,6,9], fill: 0).map { $0 }
let expected = [(1,2,3),(4,5,6),(7,8,9)]
zip(zipped,expected).forEach {
XCTAssertEqual($0.0, $1.0)
XCTAssertEqual($0.1, $1.1)
XCTAssertEqual($0.2, $1.2)
}
}

func testFirstLonger() {
let zipped = zip([1,4,7], [2,5], [3,6], fill: 0).map { $0 }
let expected = [(1,2,3),(4,5,6),(7,0,0)]
zip(zipped,expected).forEach {
XCTAssertEqual($0.0, $1.0)
XCTAssertEqual($0.1, $1.1)
XCTAssertEqual($0.2, $1.2)
}
}

func testSecondLonger() {
let zipped = zip([1,4], [2,5,8], [3,6], fill: 0).map { $0 }
let expected = [(1,2,3),(4,5,6),(0,8,0)]
zip(zipped,expected).forEach {
XCTAssertEqual($0.0, $1.0)
XCTAssertEqual($0.1, $1.1)
XCTAssertEqual($0.2, $1.2)
}
}

func testThirdLonger() {
let zipped = zip([1,4], [2,5], [3,6,9], fill: 0).map { $0 }
let expected = [(1,2,3),(4,5,6),(0,0,9)]
zip(zipped,expected).forEach {
XCTAssertEqual($0.0, $1.0)
XCTAssertEqual($0.1, $1.1)
XCTAssertEqual($0.2, $1.2)
}
}
}

0 comments on commit dc5dbd5

Please sign in to comment.