TIL how to iterate pairs if Sequence in Swift
Have been looking for iterator of pairs of sequence elements which I have used several years ago. Failed to find implementation. I found out I have a gap in knowledge and fail to write iterator on my own. I should fill in this gap. But by now here is implementation of pairs iterator borrowed from here:
extension Collection {
func pairs() -> AnySequence<(Element, Element)> {
return AnySequence(zip(self, self.dropFirst()))
}
}
As it fairly stated
this approach is not safe when applied to a
Sequence
, because it is not guaranteed that a sequence can be traversed multiple times non-destructively.
Implementation with a custom iterator type which works on sequences as well
struct PairSequence<S: Sequence>: IteratorProtocol, Sequence {
var iterator: S.Iterator
var last: S.Element?
init(seq: S) {
iterator = seq.makeIterator()
last = iterator.next()
}
mutating func next() -> (S.Element, S.Element)? {
guard let a = last, let b = iterator.next() else { return nil }
last = b
return (a, b)
}
}
extension Sequence {
func pairs() -> PairSequence<Self> {
return PairSequence(seq: self)
}
}
Reading … forgot exactly what … found out how interesting reversed()
over Sequence
is implemented in Swift. And it seems like I could really optimize it for performance as per FIXME. Sequence itself has also interesting FIXME which I could address.
Read Swift Tip: Lazy Infinite Sequences. Nice to clarify that sequence doesn’t produce element until it is requested. In following example nothing is computed until we turn results into into an Array
:
let results = (1...)
.lazy
.map { $0 * $0 }
.filter { $0 > 100 }
Array(results.prefix(10))
Exercise: improve code from this post.