0

I'm using iter(range()), but I also need to use the results twice, assuming j=iter(range(n,2n))

next(j) would be n, but then I need that certain next(j) again without stepping forward, Is that possible without further complications?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343

5 Answers5

2

You can easily write a generator which repeats each element of a given iterator twice:

def repeat_iter(iter, n = 2):
    for x in iter:
        for i in range(n):
            yield x

for x in repeat_iter(range(n)):
    print x

If what your use case requires is looking ahead, see this question for some nice solutions.

Community
  • 1
  • 1
shx2
  • 61,779
  • 13
  • 130
  • 153
0

One approach is to explicitly get two iterators, using itertools.tee:

iter1,iter2 = itertools.tee(iter(range(5,10)))

next(iter1)
Out[15]: 5

next(iter2)
Out[16]: 5

This can be more flexible depending on what you're doing, but the downside is that you need to make sure you're going 1-for-1 consuming from both iterators.

But honestly I don't think I've ever found myself doing this with range. When you assign next() to a variable, you can access it as many times as you want (a la for i in range), so...

roippi
  • 25,533
  • 4
  • 48
  • 73
0

or You can use generator statement

for i in (j for j in range(n, 2 * n) for k in range(2)):
    pass
oleg
  • 4,082
  • 16
  • 16
0

You could use zip:

for a, b in zip(range(...), range(...)):
    ...
sdasdadas
  • 23,917
  • 20
  • 63
  • 148
0

I believe shx2's answer to be the correct answer to the question.

However, in the case where

  • you only need to reuse some of the values, and do not know at the time the iterator is created which ones you need to reappear, or
  • some of the values may have to be repeated more often than others,

then here's a different generator that can react on feedback via the send() builtin.

def iter_with_standstill(iter):
    standstill = False
    for x in iter:
        while True:
            pause = yield x
            if pause is not None:
                standstill = pause
                yield None
            if not standstill:
                break

The trick used is that any call of generator.send(value) will send back the value to the generator which receives it as the result of yield. As any send() will cause the generator to also immediately run up to the next yield(), we yield(None) here to give back control immediately to the calling code. This method makes send() to truly operate as a one way operation.

Here's how to use it:

orig = range(10)
paused = iter_with_standstill(orig)

waiting = None
for x in paused:
    if x in [4,7]:
        if waiting is None:
            waiting = 3
        waiting -= 1
        if waiting > 0:
            paused.send(True)
        else:
            paused.send(False)
            waiting = None
    print(x, end=' ')
print()

The whole point of the waiting variable is to pause at the values 4 and 7, and re-iterating those values up to a total of 3 times. The output looks like:

0 1 2 3 4 4 4 5 6 7 7 7 8 9 
Community
  • 1
  • 1
cfi
  • 10,915
  • 8
  • 57
  • 103