Search code examples
pythonfor-loopiteratorgenerator

reverse next() in Python generator


Let's say that we have the following code:

gen = (x for x in range(11))

for el in gen:
    print("Printing current element: ", el) #1
    if el % 3 == 0:
        print("The next item is: ", next(gen)) #2

In this example I would like to print all the numbers from the generator in line #1 and additionally those divisible by 3 in line #2. The code must use element-wise (as opposed to index-wise) iteration. There's also a restriction that the generator gen must stay a generator (due to memory-limitations) and cannot be used e.g. as a list in reversed(list(gen)).

Current implementation makes the iteration skip numbers due to next(gen).


Solution

  • You can use itertools.tee to replicate the iterable, displace the replicated iterable by an offset of 1 with a call of next, and then use itertools.zip_longest to pair the two iterables for iteration:

    from itertools import tee, zip_longest
    gen = (x for x in range(11))
    a, b = tee(gen)
    next(b)
    for el, n in zip_longest(a, b):
        print("Printing current element: ", el)
        if el % 3 == 0:
            print("The next item is: ", n)
    

    This outputs:

    Printing current element:  0
    The next item is:  1
    Printing current element:  1
    Printing current element:  2
    Printing current element:  3
    The next item is:  4
    Printing current element:  4
    Printing current element:  5
    Printing current element:  6
    The next item is:  7
    Printing current element:  7
    Printing current element:  8
    Printing current element:  9
    The next item is:  10
    Printing current element:  10