1

I have a generator, let's say:

x = iter([1,2,3,4,5,6])

And if i want to loop 3 items at a time but step only 1 each time, i want to get:

1 2 3
2 3 4
3 4 5
5 6 

I have tried looping two at a time but it steps 2 each time:

x = iter([1,2,3,4,5,6])
x = list(x)
for i,j in zip(x[::2],x[1::2]):
    print i,j

[out]:

1 2
3 4
5 6

I have tried looping n at a time but it also steps n:

from itertools import izip_longest

def grouper(n, iterable, fillvalue=None):
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)

x = iter([1,2,3,4,5,6])

for i,j in grouper(3,x):
    print i,j
print

[out]:

Traceback (most recent call last):
  File "test.py", line 11, in <module>
    for i,j in grouper(3,x):
ValueError: too many values to unpack

I have tried just access +n each time i loop:

x = iter([1,2,3,4,5,6])
x = list(x)

for i,j in enumerate(x):
    print x[i], x[i+1], x[i+2]

[out]:

1 2 3
2 3 4
3 4 5
4 5 6
5 6
Traceback (most recent call last):
  File "test.py", line 26, in <module>
    print x[i], x[i+1], x[i+2]
IndexError: list index out of range

Question:

  • Can I not change the generator into a list before looping and accessing more than one value at a time but stepping only 1 each time?

  • Other than using the last solution i have, how to else achieve the desired iteration?

alvas
  • 115,346
  • 109
  • 446
  • 738

1 Answers1

2

You can use tee, islice and izip_longest as a base, and adapt the "stop" condition, eg:

from itertools import tee, islice, izip_longest

data = [1, 2, 3, 4, 5, 6]
iters = [islice(it, n, None) for n, it in enumerate(tee(data, 3))]
res = list(izip_longest(*iters))
# [(1, 2, 3), (2, 3, 4), (3, 4, 5), (4, 5, 6), (5, 6, None), (6, None, None)]

An example stop condition might be:

from itertools import takewhile
res = list(takewhile(lambda L: None not in L, izip_longest(*iters)))
# [(1, 2, 3), (2, 3, 4), (3, 4, 5), (4, 5, 6)]
Jon Clements
  • 138,671
  • 33
  • 247
  • 280