Transform a Swift sequence in to adjacent pairs

后端 未结 1 1222
栀梦
栀梦 2020-12-11 19:59

Given I\'ve got an array in Swift such as [1,2,3,4], a method pairs() will transform it in to the array of tuples: [(1,2), (2,3), (3,4)]

相关标签:
1条回答
  • 2020-12-11 20:20

    We can use zip() and dropFirst() if we define an extension on the Collection type:

    extension Collection {
        func pairs() -> AnySequence<(Element, Element)> {
            return AnySequence(zip(self, self.dropFirst()))
        }
    }
    

    Example:

    let array = [1, 2, 3, 4]
    for p in array.pairs() {
        print(p)
    }
    

    Output:

    (1, 2)
    (2, 3)
    (3, 4)
    

    More examples:

    print(Array("abc".pairs()))
    // [("a", "b"), ("b", "c")]
    
    print([1, 2, 3, 4, 5].pairs().map(+))
    // [3, 5, 7, 9]
    
    print([3, 1, 4, 1, 5, 9, 2].pairs().filter(<))
    // [(1, 4), (1, 5), (5, 9)]
    

    (Unlike I wrote in the first version of this answer ...) 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.

    Here is a direct implementation with a custom iterator type which works on sequences as well:

    struct PairSequence<S: Sequence>: IteratorProtocol, Sequence {
        var it: S.Iterator
        var last: S.Element?
    
        init(seq: S) {
            it = seq.makeIterator()
            last = it.next()
        }
    
        mutating func next() -> (S.Element, S.Element)? {
            guard let a = last, let b = it.next() else { return nil }
            last = b
            return (a, b)
        }
    }
    
    extension Sequence {
        func pairs() -> PairSequence<Self> {
            return PairSequence(seq: self)
        }
    }
    

    Example:

    print(Array([1, 2, 3, 4].pairs().pairs()))
    // [((1, 2), (2, 3)), ((2, 3), (3, 4))]
    
    0 讨论(0)
提交回复
热议问题