Swift:配对数组元素的最佳方式是什么

Swift: What's the best way to pair up elements of an Array

我遇到了一个需要成对迭代数组的问题。最好的方法是什么?或者,作为替代方案,将数组转换为对数组(然后可以正常迭代)的最佳方法是什么?

这是我得到的最好的。它要求 output 成为 var,而且它不是很漂亮。有没有更好的方法?

let input = [1, 2, 3, 4, 5, 6]

var output = [(Int, Int)]()

for i in stride(from: 0, to: input.count - 1, by: 2) {
    output.append((input[i], input[i+1]))
}


print(output) // [(1, 2), (3, 4), (5, 6)]

// let desiredOutput = [(1, 2), (3, 4), (5, 6)]
// print(desiredOutput)

你可以映射步幅而不是迭代它,那 允许将结果作为 常量:

let input = [1, 2, 3, 4, 5, 6]

let output = stride(from: 0, to: input.count - 1, by: 2).map {
    (input[[=10=]], input[[=10=]+1])
}

print(output) // [(1, 2), (3, 4), (5, 6)]

如果你只需要遍历对并且给定的数组很大 那么避免创建中间体可能是有利的 具有惰性映射的数组:

for (left, right) in stride(from: 0, to: input.count - 1, by: 2)
    .lazy
    .map( { (input[[=11=]], input[[=11=]+1]) } ) {

    print(left, right)

}

我认为这并不比 Martin R 的好,但 OP 似乎需要其他东西...

struct PairIterator<C: IteratorProtocol>: IteratorProtocol {
    private var baseIterator: C
    init(_ iterator: C) {
        baseIterator = iterator
    }

    mutating func next() -> (C.Element, C.Element)? {
        if let left = baseIterator.next(), let right = baseIterator.next() {
            return (left, right)
        }
        return nil
    }
}
extension Sequence {
    var pairs: AnySequence<(Self.Iterator.Element,Self.Iterator.Element)> {
        return AnySequence({PairIterator(self.makeIterator())})
    }
}

input.pairs.forEach{ print([=10=]) }

let output = input.pairs.map{[=10=]}
print(output) //->[(1, 2), (3, 4), (5, 6)]

这是@OOPer 答案的一个版本,它适用于列表中奇数个元素。当然,如果你愿意,你可以不遵守 CustomStringConvertible。但它为这个例子提供了更漂亮的输出。 :)

struct Pair<P: CustomStringConvertible>: CustomStringConvertible {
    let left: P
    let right: P?

    var description: String {
        if let right = right {
            return "(\(left.description), \(right.description)"
        }
        return "(\(left.description), nil)"
    }
}

struct PairIterator<C: IteratorProtocol>: IteratorProtocol where C.Element: CustomStringConvertible {
    private var baseIterator: C
    init(_ iterator: C) {
        baseIterator = iterator
    }

    mutating func next() -> Pair<C.Element>? {
        if let left = baseIterator.next() {
            return Pair(left: left, right: baseIterator.next())
        }
        return nil
    }
}
extension Sequence where Element: CustomStringConvertible {
    var pairs: AnySequence<Pair<Self.Element>> {
        return AnySequence({PairIterator(self.makeIterator())})
    }
}

let input: [Int] = [1,2,3,4,5,6,7]
print(input.pairs)
print(Array(input.pairs))


//output:
AnySequence<Pair<Int>>(_box: Swift._SequenceBox<Swift._ClosureBasedSequence<__lldb_expr_27.PairIterator<Swift.IndexingIterator<Swift.Array<Swift.Int>>>>>)
[(1, 2, (3, 4, (5, 6, (7, nil)]

您不需要自定义类型,例如上述答案规定的 PairIterator。获得配对序列是 one-liner:

let xs = [1, 2, 3]
for pair in zip(xs, xs.dropFirst()) {
    print(pair) // (1, 2) (2, 3)
}

如果你打算重用它,你可以在扩展中放置一个 pairs 方法:

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

现在可用

Sequence.chunks(ofCount: 2) of the swift-algorithms package

for chunk in input.chunks(ofCount: 2) {
    print(chunk)
}