【问题标题】:Transform a Swift sequence in to adjacent pairs将 Swift 序列转换为相邻对
【发布时间】:2018-03-14 08:34:18
【问题描述】:

鉴于我在 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。这将使其可用于任何序列,并与 mapreducefilter 等方法兼容。

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

【问题讨论】:

    标签: swift functional-programming sequence


    【解决方案1】:

    如果我们定义一个扩展,我们可以使用zip()dropFirst()Collection 上输入:

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

    例子:

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

    输出:

    (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)]
    

    (不像我在这个答案的第一个版本中写的......)这个 应用于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)
        }
    }
    

    例子:

    print(Array([1, 2, 3, 4].pairs().pairs()))
    // [((1, 2), (2, 3)), ((2, 3), (3, 4))]
    

    【讨论】:

    • @MartinR,你还需要添加检查Self.SubSequence.Element == Self.Element,否则pairs返回类型不匹配
    • @user28434:更新的 Swift 4 代码在我的 Xcode 9.2 中编译和运行。请注意,我将返回类型更改为(Element, SubSequence.Element) 的序列——您可以添加该约束,但您不必这样做。
    • 感谢自定义迭代器的理解。真正有用且有启发性的答案!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多