Skip to content

Instantly share code, notes, and snippets.

@koher
Last active May 30, 2020 04:16
Show Gist options
  • Save koher/550ea1e9625e66758bac85eb5063196f to your computer and use it in GitHub Desktop.
Save koher/550ea1e9625e66758bac85eb5063196f to your computer and use it in GitHub Desktop.
struct DirectProduct<Left: Sequence, Right: Sequence>: Sequence {
let left: Left
let right: Right
let iteratorType: Iterator.Type
init(_ left: Left, _ right: Right) {
self.left = left
self.right = right
iteratorType = Iterator1.self
}
func makeIterator() ->Iterator {
iteratorType.init(left, right)
}
class Iterator: IteratorProtocol {
fileprivate let left: Left
fileprivate let right: Right
required init(_ left: Left, _ right: Right) {
self.left = left
self.right = right
}
func next() -> (Left.Element, Right.Element)? {
fatalError("Override this method.")
}
}
private class Iterator1: Iterator {
private var leftIterator: Left.Iterator
private var rightIterator: Right.Iterator?
private var leftElement: Left.Element?
required init(_ left: Left, _ right: Right) {
leftIterator = left.makeIterator()
rightIterator = right.makeIterator()
leftElement = leftIterator.next()
super.init(left, right)
}
override func next() -> (Left.Element, Right.Element)? {
guard let leftElement = self.leftElement else { return nil }
if rightIterator == nil {
rightIterator = right.makeIterator()
}
guard let rightElement = rightIterator?.next() else {
rightIterator = nil
self.leftElement = leftIterator.next()
return next()
}
return (leftElement, rightElement)
}
}
}
extension DirectProduct where Left: Collection, Right: Collection, Left.Index == Int, Right.Index == Int {
init(_ left: Left, _ right: Right) {
self.left = left
self.right = right
iteratorType = Iterator2.self
}
private class Iterator2: Iterator {
private var leftIndex: Int
private var rightIndex: Int
required init(_ left: Left, _ right: Right) {
leftIndex = left.startIndex
rightIndex = right.startIndex
super.init(left, right)
}
override func next() -> (Left.Element, Right.Element)? {
guard leftIndex < left.endIndex else { return nil }
guard rightIndex < right.endIndex else {
leftIndex += 1
rightIndex = right.startIndex
return next()
}
defer { rightIndex += 1 }
return (left[leftIndex], right[rightIndex])
}
}
}
do {
let p = DirectProduct([2, 3, 5], ["X", "Y", "Z"] as Set<String>)
for (l, r) in p { print("(\(l), \(r))") }
}
print()
do {
let p = DirectProduct([2, 3, 5], ["X", "Y", "Z"])
for (l, r) in p { print("(\(l), \(r))") }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment