将Swift序列转换为相邻对

Ben*_*ohn 4 functional-programming sequence swift

鉴于我在Swift中有一个数组[1,2,3,4],一个方法pairs()会将其转换为元组数组:[(1,2), (2,3), (3,4)].

以下是一些pairs()应该如何表现的例子:

  • pairs([])应该返回,[]因为它没有对.
  • pairs([1])也应该返回[],因为它没有对.
  • pairs([1,2])应该是[(1,2)].它只有一对.

我可以编写代码来执行此操作Array,但我希望pairs()可以作为扩展Sequence,以便它返回一Sequence对.这将使得它可用在任何序列,并与方法,如兼容map,reduce,filter,等.

我如何创建Sequence这样的?我如何编写方法以Sequence这种方式转换任何方法,以便尽可能灵活地使用它?

Mar*_*n R 7

我们可以使用zip(),dropFirst()如果我们在Collection类型上定义扩展名:

extension Collection {
    func pairs() -> AnySequence<(Element, Element)> {
        return AnySequence(zip(self, self.dropFirst()))
    }
}
Run Code Online (Sandbox Code Playgroud)

例:

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

输出:

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

更多例子:

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)]
Run Code Online (Sandbox Code Playgroud)

(与我在本答案的第一个版本中所写的不同......)这种方法在应用于a时并不安全Sequence,因为无法保证序列可以非破坏性地多遍遍历 .

这是一个自定义迭代器类型的直接实现,它也适用于序列:

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

例:

print(Array([1, 2, 3, 4].pairs().pairs()))
// [((1, 2), (2, 3)), ((2, 3), (3, 4))]
Run Code Online (Sandbox Code Playgroud)