Skip to content

Instantly share code, notes, and snippets.

Last active August 29, 2015 14:10
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