Is There A Way To 'pause' Or Partially Consume A Generator In Python, Then Resume Consumption Later Where Left Off?
Solution 1:
Pausing is built-in functionality for generators. It's half the point of generators. However, range
is not a generator. It's a lazy sequence type.
If you want an object where iterating over it again will resume where you last stopped, you want an iterator over the range object:
idsx_iter = iter(range(1, math.factorial(13)))
However, it would be simpler to save the zip
iterator instead of two underlying iterators. Better yet, use enumerate
:
indexed_permutations = enumerate(itertools.permutations(strt))
You've got a lot more things that don't make sense in your code, though, like curr_idx
, which just stays at 0 forever, or your range
bounds, which produce 13!-1 indices instead of 13! indices, and really, you should be using a more efficient algorithm. For example, one based on figuring out how many permutations you skip ahead by setting the next element to a specific character, and using that to directly compute each element of the permutation.
Solution 2:
Sure you can consume part of an iterator it
, just call next(it)
to consume a single item. Or if you need to consume several at once you can write a function to consume n
items from the iterator. In both cases you just need to take care that the iterator has not reached an end (StopIteration
raised):
defconsume(iterator, n):
for i inrange(n):
try:
yieldnext(iterator)
except StopIteration:
return
Which can then be used as such:
>>> r = iter(range(5))
>>> print(list(consume(r, 3)))
[0, 1, 2]
>>> print(list(consume(r, 3)))
[3, 4]
In the end I don't see why you would need this for this particular problem, and as suggested there is a python function itertools.permutations
that already iterate over all permutations for you.
Solution 3:
The answer to the question in the title is "yes", you can pause and restart. How?
Unexpectedly (to me), apparently zip()
restarts the zipped generators despite them being previously defined (maybe someone can tell me why that happens?). So, I added main_gen = zip(idxs_gen, perms_gen)
and changed to for num, stry in zip(idxs_gen, perms_gen):
to for num, stry in main_gen:
. I then get this output, which, assuming the strings are correct, is exactly what I wanted:
1
abcdefghijklm
2
abcdefghijkml
3
4
5
abcdefghijmkl
6
7
8
9
10
abcdefghiklmj
After that change, the code looks like this:
import itertools
import math
strt = "abcdefghijklm"
dic = {}
perms_gen = itertools.permutations(strt)
idxs_gen = range(1, math.factorial(13))
main_gen = zip(idxs_gen, perms_gen)
curr_idx = 0
test_list = [1, 2, 5, 10]
defget_elems(n):
for num, stry in main_gen:
print(num)
str_stry = "".join(stry)
dic[num] = str_stry
if num == n:
return str_stry
for x in test_list:
if curr_idx < x:
print(get_elems(x))
else:
print(dic[x])
Post a Comment for "Is There A Way To 'pause' Or Partially Consume A Generator In Python, Then Resume Consumption Later Where Left Off?"