Reputation: 469
I would like to use zip to iterate in lock step over the elements of various generators. Which generators and how many of them there will be is only known at run time. However, I can't work out how to pass this into zip as any list will be interpreted as an iterable rather than the list of iterables which must be simultaneously iterated over.
What's the correct way to do this? Also, what's the correct way to unpack the outputs when their number isn't known until runtime? Below is what I have tried
from typing import List
l_1 = [1, 2, 3]
l_10 = [10, 20, 30]
l_100 = [100, 200, 300]
def gen(l_: List):
for i in l_:
yield i
# Standard: works fine as expected
for i, j, k in zip(gen(l_1), gen(l_10), gen(l_100)):
print('i={}, j={} k={}'.format(i,j,k))
# List of generators prepared at run time. Does not work
gens = [gen(l_1), gen(l_100)]
receive = [None] * len(gens)
for receive in zip(gens):
print(receive)
The output is
i=1, j=10 k=100
i=2, j=20 k=200
i=3, j=30 k=300
(<generator object gen at 0x000001C3DB93C258>,)
(<generator object gen at 0x000001C3DB93C620>,)
The desired output is
i=1, j=10 k=100
i=2, j=20 k=200
i=3, j=30 k=300
[1, 100]
[2, 200]
[3, 300]
How can I get zip to recognize that gens is not an iterable to iterate over, but rather the list of iterables which must be iterated over in lock step?
Upvotes: 2
Views: 502
Reputation: 670
It will be only a small change, to pass a list of iterables to zip you have to unpack it using *
# List of generators prepared at run time. Does not work
gens = [gen(l_1), gen(l_100)]
receive = [None] * len(gens)
for receive in zip(*gens):
print(list(receive))
edit:
since you expected lists in your output I had to explicitly convert receive to a list.
Upvotes: 5