Reputation: 1932
When I want to pass through and remove an item or items from an array (when certain conditions are met), I typically iterate backward in the C-style for-loop and remove the item by index, avoiding the problem of index numbers being changed of the next item to be processed, or the changing size of the list affecting how many times the loop is passed through. But the C for-loop has been removed in Swift 3.
Here is my Swift 2.3 code for the initialization of the loop:
for (var i = allowedItems.count - 1; i > -1; i -= 1)
Here is the monstrosity created by the Swift 3 converter:
for (i in ((-1 + 1)...allowedItems.count - 1).reversed())
This version does not compile however. ("Expected ',' separator" at the "in" operator).
I simplify the "-1 + 1" bit to zero:
for (i in (0...allowedItems.count - 1).reversed())
Now the error is "Expected Sequence expression for for-each loop".
What is the safe and hopefully reasonably elegant way of iterating backward in Swift 3, in which an index or counter variable is made available for use in specifying which item should be removed? This type of logic appears a number of places in my code so I want to make sure to find the best solution.
Thanks.
Upvotes: 0
Views: 971
Reputation: 73206
What is the safe and hopefully reasonably elegant way of iterating backward in Swift 3, in which an index or counter variable is made available for use in specifying which item should be removed?
This doesn't answer the technical question, but possibly the underlying XY problem: have you considered simply filtering your array based on the criteria "when certain conditions are met"?
func certainConditionsForKeepingAreMet(_ element: YourElementType) -> Bool { /* ... */ }
allowedItems = allowedItems.filter(certainConditionsForKeepingAreMet)
E.g.
var allowedItems = [1, 3 ,6, 2]
func certainConditionsForKeepingAreMet(_ element: Int) -> Bool { return element < 3 }
allowedItems = allowedItems.filter(certainConditionsForKeepingAreMet)
print(allowedItems) // [1, 2]
If you'd like to remove and use the removed elements (on-the-fly), you could simply pipe the elements that are to be removed to some "use this element" function, in the course of checking the conditions for the elements.
func doSomethingWith(_ element: Int) { print("Removed", element) }
func certainConditionsForKeepingAreMet(_ element: Int) -> Bool {
if element >= 3 {
doSomethingWith(element)
return false
}
return true
}
var allowedItems = [1, 3 ,6, 2]
allowedItems = allowedItems.filter(certainConditionsForKeepingAreMet)
/* Removed 3
Removed 6 */
print(allowedItems) // [1, 2]
Upvotes: 2
Reputation: 535801
What is the safe and hopefully reasonably elegant way of iterating backward in Swift 3
The built-in way is:
for i in (0 ..< allowedItems.count).reversed()
The elegant way is:
for i in allowedItems.count >>> 0
(where >>>
is the custom operator that I define here).
Upvotes: 3
Reputation: 93181
Use stride
:
for i in stride(from: allowedItems.count - 1, through: 0, by: -1) {
}
Upvotes: 2