Say I have an array [1, 2, 3, 4, 5]
. How can I iterate two at a time?
Iteration 1: (1, 2)
Iteration 2: (3, 4)
Iteration 3: (5, nil)
If the array would have an even number of elements, you would be able to write something like this:
for i in 0..<arr.count/2 {
print(arr[2*i...2*i+1])
}
However that's not always the case. Moreover, nil
is not always compatible with the type of elements in array, like the one in your example (nil
is not compatible with Int
, only with Int?
).
Another solution would be to extend Array
and add a pair()
method, which returns a tuple (tuples can be heterogenous). You can use pair
to walk within all pairs in the array, or, you can extend even more the Array
struct and add pairs()
that return an array of tuples. Note that since the second element in the tuple is an Optional
you'll need to unwrap it before use.
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)
}
Update Both above solutions can be simplified by using map
instead of manually looping:
let pairs = (0..<arr.count/2).map { (arr[$0*2], arr[$0*2+1]) }
print(pairs) // prints [(1, 2), (3, 4)]
or, for the Array
extension:
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)]
You can extend Collection
instead, to have this pair
functionality available for all collections:
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)
}
}
}