说我有一个数组[1, 2, 3, 4, 5]
。我怎样才能一次迭代两个?
Iteration 1: (1, 2)
Iteration 2: (3, 4)
Iteration 3: (5, nil)
答案 0 :(得分:18)
您可以使用名为stride(to:,by :)的渐进循环来迭代每n个元素的元素:
Xcode 8.3.2•Swift 3.1
let array = Array(1...5)
let pairs = stride(from: 0, to: array.endIndex, by: 2).map {
(array[$0], $0 < array.index(before: array.endIndex) ? array[$0.advanced(by: 1)] : nil)
} // [(.0 1, {some 2}), (.0 3, {some 4}), (.0 5, nil)]
print(pairs) // "[(1, Optional(2)), (3, Optional(4)), (5, nil)]\n"
答案 1 :(得分:3)
如果数组具有偶数个元素,您可以编写如下内容:
for i in 0..<arr.count/2 {
print(arr[2*i...2*i+1])
}
然而情况并非如此。此外,nil
并不总是与数组中的元素类型兼容,例如示例中的元素类型(nil
与Int
不兼容,仅与Int?
)兼容。
另一个解决方案是扩展Array
并添加一个pair()
方法,该方法返回一个元组(元组可以是异构的)。您可以使用pair
遍历数组中的所有对,或者,您可以扩展Array
结构,并添加返回元组数组的pairs()
。请注意,由于元组中的第二个元素是Optional
,因此您需要在使用前将其解包。
extension Array {
func pair(at i: Index) -> (Element, Element?) {
return (self[i], i < self.count - 1 ? self[i+1] : nil)
}
func pairs() -> [(Element, Element?)] {
guard !isEmpty else { return [] }
var result = [(Element, Element?)]()
for i in 0...arr.count/2 {
result.append(self.pair(at: 2*i))
}
return result
}
}
let arr = [1, 2, 3, 4, 5]
for i in 0...arr.count/2 {
print(arr.pair(at: 2*i))
}
for pair in arr.pairs() {
print(pair)
}
更新使用map
代替手动循环,可以简化上述两种解决方案:
let pairs = (0..<arr.count/2).map { (arr[$0*2], arr[$0*2+1]) }
print(pairs) // prints [(1, 2), (3, 4)]
或,对于Array
扩展程序:
extension Array {
func pair(at i: Index) -> (Element, Element?) {
return (self[i], i < self.count - 1 ? self[i+1] : nil)
}
func pairs() -> [(Element, Element?)] {
guard !isEmpty else { return [] }
return (0..<(arr.count/2 + arr.count%2)).map { pair(at: $0*2) }
}
}
let arr = [1, 2, 3, 4, 5]
print(arr.pairs()) // [(1, Optional(2)), (3, Optional(4)), (5, nil)]
您可以扩展Collection
,以便为所有馆藏提供此pair
功能:
extension Collection {
func pairs() -> [(Element, Element?)] {
guard !isEmpty else { return [] }
return (0..<count/2+count%2).map {
let i1 = index(startIndex, offsetBy: $0*2)
let i2 = index(startIndex, offsetBy: $0*2+1)
return (self[i1], i2 < endIndex ? self[i2] : nil)
}
}
}
答案 2 :(得分:3)
您可以使用sequence()
和迭代器的next()
方法进行迭代
对成对的连续元素。这适用于任意序列,
不仅是数组:
let a = "ABCDE"
for pair in sequence(state: a.makeIterator(), next: { it in
it.next().map { ($0, it.next()) }
}) {
print(pair)
}
输出:
("A", Optional("B")) ("C", Optional("D")) ("E", nil)
“外部” it.next()
产生偶数位置的元素,或nil
(在这种情况下,it.next().map { }
的计算结果也为nil
,并且
序列终止)。 “内部” it.next()
产生元素
在奇数位置或nil
上。
作为任意序列的扩展方法:
extension Sequence {
func pairs() -> AnyIterator<(Element, Element?)> {
return AnyIterator(sequence(state: makeIterator(), next: { it in
it.next().map { ($0, it.next()) }
}))
}
}
示例:
let seq = (1...).prefix(5)
for pair in seq.pairs() { print(pair) }
请注意,这些对是 lazyly 生成的,没有中间数组 被建造。 如果您想要一个包含所有对的数组,那么
let pairs = Array([1, 2, 3, 4, 5].pairs())
print(pairs) // [(1, Optional(2)), (3, Optional(4)), (5, nil)]
完成工作。
答案 3 :(得分:2)
我个人不喜欢在列表的一半中循环(主要是因为划分),所以我喜欢这样做:
let array = [1,2,3,4,5];
var i = 0;
while i < array.count {
var a = array[i];
var b : Int? = nil;
if i + 1 < array.count {
b = array[i+1];
}
print("(\(a), \(b))");
i += 2;
}
通过递增2来循环遍历数组。
如果您想在元素中使用nil,则需要使用选项。
答案 4 :(得分:2)
这与询问的内容不同,但是我在Sequence上使用了扩展名,该扩展名生成了将数组按任意所需大小分块的数组数组:
extension Sequence {
func clump(by clumpsize:Int) -> [[Element]] {
let slices : [[Element]] = self.reduce(into:[]) {
memo, cur in
if memo.count == 0 {
return memo.append([cur])
}
if memo.last!.count < clumpsize {
memo.append(memo.removeLast() + [cur])
} else {
memo.append([cur])
}
}
return slices
}
}
所以[1, 2, 3, 4, 5].clump(by:2)
产生[[1, 2], [3, 4], [5]]
,现在您可以根据需要进行迭代。
答案 5 :(得分:0)
一种方法是将数组封装在一个类中。获取项目对的返回值将是选项,以防止超出范围的呼叫。
示例:
class Pairs {
let source = [1, 2, 3, 4, 5] // Or set with init()
var offset = 0
func nextpair() -> (Int?, Int?) {
var first: Int? = nil
var second: Int? = nil
if offset < source.count {
first = source[offset]
offset++
}
if offset < source.count {
second = source[offset]
offset++
}
return (first, second)
}
}
答案 6 :(得分:0)
扩展以拆分数组。
extension Array {
func chunked(into size: Int) -> [[Element]] {
return stride(from: 0, to: count, by: size).map {
Array(self[$0 ..< Swift.min($0 + size, count)]) }
}
}
let result = [1...10].chunked(into: 2)
答案 7 :(得分:0)
这是我的解决方案,包含一个 reduce
和几个 guard
extension Array {
var touplesOfTwo: [(Element,Element?)] {
self.reduce(into: [(Element,Element?)]()) {
guard let last = $0.last else { $0.append( ($1,nil) ); return }
let lastIndex = $0.count - 1
guard let _ = last.1 else { $0[lastIndex].1 = $1; return }
$0.append( ($1,nil) )
}
}
}
let list = [1,4,3,7,2,9,6,5]
let queues = list.map { $0 }
let touplesList = queues.touplesOfTwo
print("\(touplesList)")
// [(1, Optional(4)), (3, Optional(7)), (2, Optional(9)), (6, Optional(5))]