Skip to content

Instantly share code, notes, and snippets.

@dennisvennink
Last active November 8, 2018 21:57
Show Gist options
  • Save dennisvennink/a64f6af5d846713b72effb47fa7eb9fb to your computer and use it in GitHub Desktop.
Save dennisvennink/a64f6af5d846713b72effb47fa7eb9fb to your computer and use it in GitHub Desktop.
Implementations of `zipLongest(_:_:)` Without Any Custom Types
// Using `sequence(state:next:).lazy`.
func zipLongest <Sequence1: Sequence, Sequence2: Sequence>
(_ sequence1: Sequence1, _ sequence2: Sequence2) ->
LazySequence<UnfoldSequence<(Sequence1.Element?, Sequence2.Element?),
(Sequence1.Iterator, Sequence2.Iterator)>> {
return sequence(state: (sequence1.makeIterator(), sequence2.makeIterator())) {
let element1 = $0.0.next()
let element2 = $0.1.next()
return element1 == nil && element2 == nil ? nil : (element1, element2)
}.lazy
}
// Using `AnySequence(_:).lazy`.
func zipLongest <Sequence1: Sequence, Sequence2: Sequence>
(_ sequence1: Sequence1, _ sequence2: Sequence2) ->
LazySequence<AnySequence<(Sequence1.Element?, Sequence2.Element?)>> {
var iterator1 = sequence1.makeIterator()
var iterator2 = sequence2.makeIterator()
return AnySequence {
AnyIterator {
let element1 = iterator1.next()
let element2 = iterator2.next()
return element1 == nil && element2 == nil ? nil : (element1, element2)
}
}.lazy
}
// Using a `while` loop.
func zipLongest <Sequence1: Sequence, Sequence2: Sequence>
(_ sequence1: Sequence1, _ sequence2: Sequence2) ->
[(Sequence1.Element?, Sequence2.Element?)] {
var iterator1 = sequence1.makeIterator()
var iterator2 = sequence2.makeIterator()
var result = [(Sequence1.Element?, Sequence2.Element?)]()
while true {
let element1 = iterator1.next()
let element2 = iterator2.next()
if element1 == nil && element2 == nil {
break
} else {
result.append((element1, element2))
}
}
return result
}
// Using recursion.
func zipLongest <Sequence1: Sequence, Sequence2: Sequence>
(_ sequence1: Sequence1, _ sequence2: Sequence2) ->
[(Sequence1.Element?, Sequence2.Element?)] {
switch (sequence1.headTail, sequence2.headTail) {
case (.none, .none): return []
case (.none, let .some(y, ys)): return [(nil, y)] + zipLongest([], ys)
case (let .some(x, xs), .none): return [(x, nil)] + zipLongest(xs, [])
case let (.some(x, xs), .some(y, ys)): return [(x, y)] + zipLongest(xs, ys)
}
}
extension Sequence {
var headTail: (head: Element, tail: SubSequence)? {
var head: Element?
let tail = drop { head == nil ? { head = $0 ; return true }($0) : false }
return head != nil ? nil : (head: head!, tail: tail)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment