Resetting An Iterator, Which Is A Map Object?
Solution 1:
Iterating an iterator/generator consumes the values from it (infinite generators being an exception), meaning that they will no longer be available on future iterations (as you've seen). For a typical iterator/generator in Python, the only true way to "restart" it is to re-initialize it.
>>> sol = map(pow, [1, 2, 3], [4, 5, 6])
>>> list(sol)
[1, 32, 729]
>>> next(sol)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> sol = map(pow, [1, 2, 3], [4, 5, 6])
>>> next(sol)
1
There are ways that you can work with the iterator to make it reusable though, such as with itertools.tee
(as mentioned by one of the answers to the question linked by @JanChristophTerasa), or to convert the iterator into a list, which will persist its data.
>>> from itertools import tee
>>> sol = map(pow, [1, 2, 3], [4, 5, 6])
>>> a, b = tee(sol, 2)
>>> list(a)
[1, 32, 729]
>>> list(b)
[1, 32, 729]
>>> list(a)
[]
with tee
though, both a
and b
will still be iterators, so you'll have the same problem with them.
Another common way to handle this is with list()
sol = list(map(pow, [1, 2, 3], [4, 5, 6]))
>>> sol
[1, 32, 729]
>>> sol
[1, 32, 729]
Now, sol
is a list of values instead of an iterator, which means you can iterate it as many times as you want - the values will remain there. This does mean you can't use next
with it (in the sense of next(sol)
), but you can get an iterator back from your new list with iter(sol)
if you need an iterator specifically.
Edit
I saw itertools.cycle
mentioned in the comments, which is also a valid option so I thought I might add some info on it here as well.
itertools.cycle
is one of those infinite generators I mentioned at the start. It is still an iterator, but in a way that you'll never run out of values.
>>> from itertools import cycle
>>> sol = map(pow, [1, 2, 3], [4, 5, 6])
>>> infinite = cycle(sol)
>>> for _ in range(5):
... print(next(infinite))
...
1
32
729
1
32
>>>
A few notes on this - after iterating infinite
N times, it will be positioned after whatever the last value was pulled from it. Iterating it again later will resume from that position, not from the start.
Also, and this is very important, do not iterate an infinite generator in an unbounded fashion, like list(infinite)
or for x in infinite:
, or you're gonna have a bad time.
Solution 2:
To achieve the effect you described on the OP, you can use itertools.cycle()
. Something like this:
Python 3.7.6 (default, Jan 30 2020, 09:44:41)
[GCC 9.2.1 20190827 (Red Hat 9.2.1-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from itertools import cycle
>>> c = cycle(map(pow,[1,2,3],[4,5,6]))
>>> next(c)
1
>>> next(c)
32
>>> next(c)
729
>>> next(c)
1
>>> next(c)
32
>>>
But take into consideration the comments on the OP before you choose this approach.
Post a Comment for "Resetting An Iterator, Which Is A Map Object?"