Reputation: 1968
So, I have a for-loop that looks similar to this:
for var i = 0; i < results.count ; i += 1 {
if (results[i] < 5) {
results.removeAtIndex(i)
i -= 1
}
}
This used to work. But when I changed it to the preferred Swift 3.0 syntax:
for var i in 0..<results.count {
if (results[i] < 5) {
results.removeAtIndex(i)
i -= 1
}
}
I get an array IOOBE exception because it doesn't re-check the count and continues on until the original results.count
.
How do I fix this? It works now, but I don't want to get into trouble in the future.
Upvotes: 55
Views: 137686
Reputation: 769
Could you use a filter
instead?
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let greaterThan4 = numbers.filter{$0 >= 5}
print(greaterThan4)
Upvotes: 19
Reputation: 16292
While the solution making use of filter
is a fine solution and it's more Swift-ly, there is another way, if making use of for-in
is, nonetheless, still desired:
func removeBelow(value: Int) {
var results = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
for i in (0 ..< results.count).reversed() {
if (results[i] < value) {
results.remove(at: i)
}
}
print(results)
}
removeBelow(value: 5)
Result:
[5, 6, 7, 8, 9, 10]
The problem with removeAtIndex
within the loop is that it will not cause the array to re-index itself in-place and thus causing an array out of bounds exception due to count
not being updated.
By traversing backwards, the out of bounds exception can thus be avoided.
Upvotes: 86
Reputation: 39
If your loop goes forward...
for var i in (0..<results.count) where results.indices.contains(i) {
//if the index doesn't exist, the loop will be stopped.
if (results[i] < 5) {
results.removeAtIndex(i)
}
}
Upvotes: 1
Reputation: 23512
If you want to continue using a for
-loop, you can enumerate over both index and element using enumerate
:
for (index, element) in results.enumerate() {
if (element < 5) {
results.removeAtIndex(index)
}
}
Although depending on what you're doing in your loop, the filter
method might be a better idea.
Upvotes: 15