Re-using zip iterator in python 3
Question:
I have the zip
object:
L_RANGES = zip(range(10, 20), range(11, 21))
First call of L_RANGES
is ok:
print(type(L_RANGES))
for a, b in L_RANGES:
print(a, b)
Output:
<class 'zip'>
10 11
11 12
12 13
13 14
14 15
15 16
16 17
17 18
18 19
19 20
Bu the next calls do not display anything. Is there any way to maintain or reset that. So far I can just convert it to the list:
L_RANGES = list(zip(range(10, 20), range(11, 21)))
Answers:
In Python 3.x zip()
returns iterator that gets exhausted.
Simplest way to avoid it is:
L_RANGES = list(zip(range(10, 20), range(11, 21)))
An iterator, once exhausted, may not be reused. In Python 3.x, zip
returns an iterator. One solution is to use itertools.tee
to copy an iterator n times.
For example, setting n = 2
, we can do the following:
from itertools import tee
L_RANGES_1, L_RANGES_2 = tee(zip(range(10, 20), range(11, 21)), 2)
for item in L_RANGES_1:
# do something
for item in L_RANGES_2:
# do something else
Conversion to a list
allows use an arbitrary number of times, but is inadvisable for large iterables due to the memory overhead.
For a large number of copies, you can use a dictionary. For example:
L_RANGES = dict(zip(range(1000), tee(zip(range(10, 20), range(11, 21)), 1000)))
If you were to create a generator each time you loop, that would solve everything, because you could reuse that multiple times. For that, convert L_RANGES
from a simple generator to a lambda
creating generators, but don’t forget to “call” it each time with ()
:
L_RANGES = lambda: zip(range(10, 20), range(11, 21))
for a, b in L_RANGES():
print(a, b)
for a, b in L_RANGES():
print(a, b)
#works as many times as you want
Compared to the other answers this doesn’t take up memory (which is the downside of converting to a list) and doesn’t require multiple variables for each time you want to loop (by using tee
) which makes this way more flexible (you can iterate 1000 times if necessary, without creating L_RANGES_1...L_RANGES_999
) for example:
for i in range(1000):
for a, b in L_RANGES():
print(a, b)
I have the zip
object:
L_RANGES = zip(range(10, 20), range(11, 21))
First call of L_RANGES
is ok:
print(type(L_RANGES))
for a, b in L_RANGES:
print(a, b)
Output:
<class 'zip'>
10 11
11 12
12 13
13 14
14 15
15 16
16 17
17 18
18 19
19 20
Bu the next calls do not display anything. Is there any way to maintain or reset that. So far I can just convert it to the list:
L_RANGES = list(zip(range(10, 20), range(11, 21)))
In Python 3.x zip()
returns iterator that gets exhausted.
Simplest way to avoid it is:
L_RANGES = list(zip(range(10, 20), range(11, 21)))
An iterator, once exhausted, may not be reused. In Python 3.x, zip
returns an iterator. One solution is to use itertools.tee
to copy an iterator n times.
For example, setting n = 2
, we can do the following:
from itertools import tee
L_RANGES_1, L_RANGES_2 = tee(zip(range(10, 20), range(11, 21)), 2)
for item in L_RANGES_1:
# do something
for item in L_RANGES_2:
# do something else
Conversion to a list
allows use an arbitrary number of times, but is inadvisable for large iterables due to the memory overhead.
For a large number of copies, you can use a dictionary. For example:
L_RANGES = dict(zip(range(1000), tee(zip(range(10, 20), range(11, 21)), 1000)))
If you were to create a generator each time you loop, that would solve everything, because you could reuse that multiple times. For that, convert L_RANGES
from a simple generator to a lambda
creating generators, but don’t forget to “call” it each time with ()
:
L_RANGES = lambda: zip(range(10, 20), range(11, 21))
for a, b in L_RANGES():
print(a, b)
for a, b in L_RANGES():
print(a, b)
#works as many times as you want
Compared to the other answers this doesn’t take up memory (which is the downside of converting to a list) and doesn’t require multiple variables for each time you want to loop (by using tee
) which makes this way more flexible (you can iterate 1000 times if necessary, without creating L_RANGES_1...L_RANGES_999
) for example:
for i in range(1000):
for a, b in L_RANGES():
print(a, b)