skip to Main Content

I try to add 1 to i in a loop for in a specific moment? When I do this, it comes to the "normal" value instantly at the begining of the loop.

for var i in (0..<10)
    {
    if (i == 2)
       {
       i += 1
       }
    }

EDIT:

Concret code:

                   for var i in (0..<models.count) 
                    {
                        if (i > 0 && models[i].label1 == models[i-1].label1)
                        {
                            models[i-1].slots.append(contentsOf: models[i].slots)
                            models.remove(at: i)
                            i -= 1
                           
                        }
                    }

3

Answers


  1. The for loop sets the value of i each time through.

    So,

        for var i in (0..<10)
        {
            // the for loop sets i to the next value in 0 to 9
            print(i)
            if (i == 2)
            {
                // print current value of i
                print("a:", i)
                i += 1
                // print current value of i
                print("b:", i)
            }
        }
    

    Inside your if (i == 2) block, you change the value of i but then the for loop changes it right back to the next value in the enumeration of 0 to 9.

    The debug output from the above code will look like this:

    0
    1
    2
    a: 2
    b: 3
    3
    4
    5
    6
    7
    8
    9
    

    To make it more obvious, change i += 1 to i += 4

    Output:

    0
    1
    2
    a: 2
    b: 6
    3
    4
    5
    6
    7
    8
    9
    

    Editfor a little more clarification…

    From the Swift Docs:

    For-In Loops

    You use the for-in loop to iterate over a sequence, such as items in an array, ranges of numbers, or characters in a string.

    Both of these loops:

    for i in 0..<3 {
        print("i =", i)
    }
    
    for i in [0, 1, 2] {
        print("i =", i)
    }
    

    will output this:

    i = 0
    i = 1
    i = 2
    

    and this loop:

    for i in [0, 2, 4] {
        print("i =", i)
    }
    

    will output this:

    i = 0
    i = 2
    i = 4
    

    because the for-in loop is iterating over the sequence.

    In either case, if we try to modify i inside the loop, we’ll see this in Xcode:

    enter image description here

    If we change i to a var:

    for var i in 0..<3 {
        print("a: i =", i)
        i = 7
        print("b: i =", i)
    }
    

    we can compile and run the code, but… each time through the loop i will be assigned the next value in the iteration, and we’ll get this:

    a: i = 0
    b: i = 7
    a: i = 1
    b: i = 7
    a: i = 2
    b: i = 7
    

    As Duncan C explained, if we want to actually modify i, the proper thing to do is use a while loop.

    So… why can we do this in other languages (such as Objective-C):

    for (int i = 0; i < 3; i++) {
        NSLog(@"a: i = %d", i);
        i = 7;
        NSLog(@"b: i = %d", i);
    }
    

    and get this output:

    a: i = 0
    b: i = 7
    

    and the loop exits?

    That’s because this:

    enter image description here

    is a more concise yet functionally equivalent way of writing this:

    enter image description here

    The Swift For-In loop is much more similar to the Objective-C For-In Fast Enumeration loop:

    for (NSNumber *n in @[@0, @1, @2]) {
        NSLog(@"n = %@", n);
    }
    

    outputs:

    n = 0
    n = 1
    n = 2
    

    and, if we try to modify n inside the loop:

    enter image description here

    so we make it __strong:

    for (__strong NSNumber *n in @[@0, @1, @2]) {
        NSLog(@"a: n = %@", n);
        n = @7;
        NSLog(@"b: n = %@", n);
    }
    

    and the output is – as you might guess:

    a: n = 0
    b: n = 7
    a: n = 1
    b: n = 7
    a: n = 2
    b: n = 7
    

    Hope that helps a bit.

    Login or Signup to reply.
  2. In for loops in Swift, the variable (i) is treated as a let constant, and you cannot mutate it inside the loop.

    That seems right. Being able to mutate a loop variable inside the loop can lead to all sorts of unexpected side-effects.

    You can use a while loop to get the same effect:

    The following works:

    var i = 0
    while i < 10  {
        print(i)
        if i.isMultiple(of: 2) && Int.random(in: 1...3) == 2 {
            i -= 1
        }
        i += 1
    }
    print("Done")
    

    This code throws a compiler error:

    for index in 1...10 {
        if index.isMultiple(of: 3) {
            index += 1 // <- Error: "left side of mutating operator isn't mutable: 'index' is a 'let' constant"
            print(index)
        }
    }
    
    Login or Signup to reply.
  3. The problem is caused because the i is scoped to the block of the loop. Each time round you actually get a new i.

    There are three solutions.

    The first is to use a while loop as per Duncan C’s answer.

    The second is to maintain a separate index and still use a for loop, but that’s really just the same as the first one

    The best answer IMO is to count downwards from the end.

    for i in (1 ..< models.count).reversed()
    {
        if (models[i].label1 == models[i-1].label1)
        {
            models[i-1].slots.append(contentsOf: models[i].slots)
            models.remove(at: i)
        }
    }
    

    Of course, reversing a list of numbers gets expensive for long lists, so you might consider using stride

    for i in stride(from: models.count - 1, to: 0, by: -1)
    {
        if (models[i].label1 == models[i-1].label1)
        {
            models[i-1].slots.append(contentsOf: models[i].slots)
            models.remove(at: i)
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search