Search code examples
pythonfor-loopiteratorgenerator

Looping on more than one variable (not all of them are finite or even known sequences) in python


How to loop on more than one variable in python if not all of them are already known or finite sequences?

In other words, How to create a similar code to this C++ code in python?

int y = 7;
int z = 3, dz = 5;
for (int x = 0; x < 20; ++x, ++y, z += dz){
    cout << x << " " << y << " " << z << endl;
}

In this example, x boundaries are well defined. However, y and z are not.


Solution

  • I managed to do that by combining 2 features in python: the builtin function zip() and the generator functions.

    I first defined a generator increment_by(base, addon) as follows:

    def increment_by(base, addon):
        while True:
            yield base
            base += addon
    

    Then I passed it, along with other generators / sequences to the zip function. Finally I loop on the next value from zip().

    N.B. One of the sequences generators should be finite, otherwise, your application might crash.

    y, z, dz = 7, 3, 5
    print('==>', y, z)
    for x, y, z in zip(range(20), increment_by(y, 1), increment_by(z, dz)):
        print(x, y, z)
    print()
    print('==>', y, z)
    

    The output was

    ==> 7 3
    0 7 3
    1 8 8
    2 9 13
    3 10 18
    4 11 23
    5 12 28
    6 13 33
    7 14 38
    8 15 43
    9 16 48
    10 17 53
    11 18 58
    12 19 63
    13 20 68
    14 21 73
    15 22 78
    16 23 83
    17 24 88
    18 25 93
    19 26 98
    ==> 26 98
    

    The nice thing here is that by using the same variable name before the in operator, I can use the same variable value within and after the loop. This is possible because the interpreter takes the generator object, invoke next() on it, and return with the yielded value to in a way suitable for assignment to any variable, including the original variable itself. Hence, using the original variable will make its value get updated every iteration, and stay updated outside the loop.

    UPDATE: As @Iain Shelvington mentioned, there is a builtin generator function (itertools.count(start=0, step=1)) that does exactly the same functionality and it takes the same parameters in the same order as increment_by(base, addon).