Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Zip2 that uses optionals for unequal lengths, plus using it to implement equal for sequences
public struct ZipOuter2<S1: SequenceType, S2: SequenceType>: SequenceType {
private let _s1: S1
private let _s2: S2
init(_ s1: S1, _ s2: S2) {
_s1 = s1
_s2 = s2
public typealias Generator = GeneratorOf<(S1.Generator.Element?, S2.Generator.Element?)>
public func generate() -> Generator {
// the requirement to never call .next() a second time
// after it returns nil complicates this a bit
var g1: S1.Generator? = _s1.generate()
var g2: S2.Generator? = _s2.generate()
return GeneratorOf {
switch(g1?.next(),g2?.next()) {
case (.None,.None): return nil // both generators are exhausted
case let (.Some(x),.None): g2 = nil; return (x,nil)
case let (.None,.Some(y)): g1 = nil; return (nil,y)
case (let x, let y): return (x,y)
// the std lib equal that takes a comparator requires the sequences contain the same
// type, which shouldn't be necessary since the comparator could cater for that
public func equal<S1: SequenceType, S2: SequenceType>(a1: S1, a2: S2, isEquivalent: (S1.Generator.Element, S2.Generator.Element) -> Bool) -> Bool {
for pair in ZipOuter2(a1, a2) {
switch pair {
case (.None,.None): assertionFailure("should never happen")
case (.None, .Some): return false
case (.Some, .None): return false
case let (.Some(x),.Some(y)): if !isEquivalent(x,y) { return false }
return true
let eqIntString: (Int,String)->Bool = { i,s in s.toInt().map { $0 == i } ?? false }
equal([1,2,3], ["1","2","3"], eqIntString)
equal(1...3, ["1","2","3"], eqIntString)
equal([Int](),[String](), eqIntString)
!equal([1,2,3,4], ["1","2","3"], eqIntString)
!equal([1,2,3], ["1","2","3","4"], eqIntString)
!equal([1,1,3], ["1","2","3"], eqIntString)
!equal([1,2,3], ["1","3","3"], eqIntString)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment