I came across a problem that required iterating over an array in pairs. What's the best way to do this? Or, as an alternative, what's the best way of transforming an Array into an Array of pairs (which could then be iterated normally)?
我遇到了一个需要成对迭代数组的问题。最好的方法是什么?或者,作为替代方案,将数组转换为数组对的最佳方法是什么(然后可以正常迭代)?
Here's the best I got. It requires output
to be a var
, and it's not really pretty. Is there a better way?
这是我得到的最好的。它需要输出为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)
2 个解决方案
#1
16
You can map the stride instead of iterating it, that allows to get the result as a constant:
您可以映射步幅而不是迭代它,这样可以将结果作为常量获取:
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)]
If you only need to iterate over the pairs and the given array is large then it may be advantageous to avoid the creation of an intermediate array with a lazy mapping:
如果您只需要迭代对并且给定的数组很大,那么避免使用延迟映射创建中间数组可能是有利的:
for (left, right) in stride(from: 0, to: input.count - 1, by: 2)
.lazy
.map( { (input[$0], input[$0+1]) } ) {
print(left, right)
}
#2
3
I don't think this is any better than Martin R's, but seems the OP needs something else...
我不认为这比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)]
#1
16
You can map the stride instead of iterating it, that allows to get the result as a constant:
您可以映射步幅而不是迭代它,这样可以将结果作为常量获取:
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)]
If you only need to iterate over the pairs and the given array is large then it may be advantageous to avoid the creation of an intermediate array with a lazy mapping:
如果您只需要迭代对并且给定的数组很大,那么避免使用延迟映射创建中间数组可能是有利的:
for (left, right) in stride(from: 0, to: input.count - 1, by: 2)
.lazy
.map( { (input[$0], input[$0+1]) } ) {
print(left, right)
}
#2
3
I don't think this is any better than Martin R's, but seems the OP needs something else...
我不认为这比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)]