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

时间:2016-11-28 10:10:19

标签: arrays swift functional-programming immutability

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

这是我得到的最好的。它需要outputvar,并且它不是很漂亮。还有更好的方法吗?

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)

5 个答案:

答案 0 :(得分:19)

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

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

let output = stride(from: 0, to: input.count - 1, by: 2).map {
    (input[$0], input[$0+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[$0], input[$0+1]) } ) {

    print(left, right)

}

答案 1 :(得分:4)

我认为这不比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($0) }

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

答案 2 :(得分:3)

这是@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)]

答案 3 :(得分:1)

现在可以作为

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

for (left, right) in input.chunks(ofCount: 2) {
    print(left, right)
}

答案 4 :(得分:0)

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

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

如果您打算重复使用该方法,可以在扩展内放置一个pair方法:

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