How do I write a for-loop in Swift 3 for an array that I modify during the for loop?

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.


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.


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)

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.