cdub
cdub

Reputation: 180

Alternative for Swift C-style loop when iterator was changed conditionally within the loop

With Swift 2.2 deprecating C-style loops, I now need to find an alternative for a for-loop where the iterator was changed within the loop conditionally. What is now the Swifty way for doing:

    for var i = 1; i <= 10; i++ {
        //do stuff
        if checkCondition() {
            i--
        }
    }

Upvotes: 0

Views: 214

Answers (3)

M. Solle
M. Solle

Reputation: 44

C's For loop will simply be replaced with Swift's For-In Loops. That means that this:

for var i = 1; i <= 10; i++ {
    //do stuff
    if checkCondition() {
        i--
    }
}

Becomes This:

for i in 1...10 {
    //do stuff
    if checkCondition() {
        i-=i
    }
}

The 1...10 is the range over which we want to iterate: from 1 to 10.

Upvotes: -1

rickster
rickster

Reputation: 126157

The iterator variable declared in a for loop is scoped to a single pass through that loop, so if you want to change it across multiple passes through the loop you'll need to use a while loop instead.

Also, since your intention seems to be "increment the loop counter only if checkCondition() is false" you can do that more clearly with a single, conditional increment, instead of using a decrement to undo your increment. Here are a couple of examples of that:

var i = 1
while i <= 10 {
    if !checkCondition() {
        i += 1
    }
}

var j = 1
while j <= 10 {
    j = checkCondition() ? j : j + 1
}

And a one that's maybe a little silly, but might come in handy if you do this sort of thing a lot:

extension IntegerType {
    mutating func incrementIf(@autoclosure condition: () -> Bool) {
        if condition() {
            self = self + 1
        }
    }
}
var k = 1
while k <= 10 {
    k.incrementIf(!checkCondition())
}

Of course, there's the further question of whether you want to be following this counter-based pattern at all (as @Sulthan notes in comments). Part of why Swift is doing away with the C-style for loop is that many loops with a counter are actually using that counter to index a collection, which is a pattern better served by collection iteration. So you might instead do something like:

for item in collection {
    process(item)
    if item.needsMoreProcessing {
        process(item) // some more
    }
}

for item in collection {
    while item.needsProcessing {
        process(item)
    }
}

If something like this is what your loop is actually doing, writing it this way makes your purpose much more clear to other readers of your code (including your future self).

Upvotes: 3

dfrib
dfrib

Reputation: 73196

With dynamic update of the iterate within the loop block, you're probably best off to use a similar while loop

var i = 1
while(i <= 10) {
    if checkCondition() {
        i -= 1
    }
    print(i)
    i += 1
}

Upvotes: 3

Related Questions