假设我有一个数组 [1, 2, 3, 4, 5]
。如何每次迭代两个元素?
Iteration 1: (1, 2)
Iteration 2: (3, 4)
Iteration 3: (5, nil)
假设我有一个数组 [1, 2, 3, 4, 5]
。如何每次迭代两个元素?
Iteration 1: (1, 2)
Iteration 2: (3, 4)
Iteration 3: (5, nil)
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"
为了迭代您的集合子序列而不是元组:
extension Collection {
func unfoldSubSequences(limitedTo maxLength: Int) -> UnfoldSequence<SubSequence,Index> {
sequence(state: startIndex) { start in
guard start < self.endIndex else { return nil }
let end = self.index(start, offsetBy: maxLength, limitedBy: self.endIndex) ?? self.endIndex
defer { start = end }
return self[start..<end]
}
}
}
let array = Array(1...5)
for subsequence in array.unfoldSubSequences(limitedTo: 2) {
print(subsequence) // [1, 2] [3, 4] [5]
}
这可以适用于任何类型的集合:
let string = "12345"
for substring in string.unfoldSubSequences(limitedTo: 2) {
print(substring) // "12" "34" "5"
}
sequence()
和迭代器的next()
方法来迭代连续元素对。这适用于任意序列,而不仅仅是数组:let a = "ABCDE"
for pair in sequence(state: a.makeIterator(), next: { it in
it.next().map { ($0, it.next()) }
}) {
print(pair)
}
输出:
("A", 可选的("B")) ("C", 可选的("D")) ("E", 空)
“外部”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) }
let pairs = Array([1, 2, 3, 4, 5].pairs())
print(pairs) // [(1, Optional(2)), (3, Optional(4)), (5, nil)]
each_slice
,在这里我们不仅限于成对,而且可以将序列分成任意给定长度的子序列(三元组等)。 - mattit.next().map { }
中,由于 it.next()
返回可选项,难道不需要使用可选链吗? - fumoboy007Optional.map
。 - Martin R虽然这不完全符合要求,但我使用了一个序列扩展来生成一个数组的数组,通过任何所需的大小对原始序列进行分块:
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]]
,现在您可以遍历它(如果您喜欢)。将数组拆分的扩展。
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)
代码示例:
for i in 0..<arr.count/2 {
print(arr[2*i...2*i+1])
}
nil
并不总与数组中元素的类型兼容,比如在你的例子中(nil
与Int
不兼容,只与Int?
兼容)。Array
并添加一个pair()
方法,该方法返回一个元组(元组可以是异构的)。您可以使用pair
来遍历数组中的所有对,或者您甚至可以进一步扩展Array
结构并添加pairs()
以返回元组的数组。请注意,由于元组中的第二个元素是可选的,因此您需要在使用之前将其解包。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(after: i1)
return (self[i1], i2 < endIndex ? self[i2] : nil)
}
}
}
let i2 = index(after: i1)
呢? - Leo Dabus我个人不喜欢循环遍历一半的列表(主要是因为要进行除法运算),所以这是我喜欢的做法:
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,需要使用可选项。
这是我的解决方案,使用了一个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))]
reduce(into: [])
。 - Leo Dabusguard let last = $0.last, last.1 == nil else {
$0.append(($1,nil))
return
}
$0[$0.index(before: $0.endIndex)].1 = $1
- Leo Dabusclass 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)
}
}