3

I need to get the result of each generator at the same time but the number of generators can be anything from 1 to 10.

My question is probably related to this question: Loop over two generator together

Is it possible to generalize this for an arbitrary number of generators which are in a list? Something like (not working)

generators = [gen1, gen2, gen3, ....]
for *data in *generators:
    #do something, e.g. average data along axis and write out
M. Beining
  • 99
  • 1
  • 9
  • `chain` consumes the iterables one _after_ the other, it's the wrong tool. – alexis Feb 13 '19 at 15:00
  • Unfortunately not because it says "returns elements from the first iterable until it is exhausted, then proceeds to the next iterable". But it should return the first element of each iterable and then the second and so on – M. Beining Feb 13 '19 at 15:00
  • You might need to look into `zip` as it is posted in an answer to question you linked in your question. – Austin Feb 13 '19 at 15:01
  • 1
    `for a, b in zip(it1, it2)` to consume them at the same time, `itertools.chain` to iterate the first then the second and so on. – Benoît P Feb 13 '19 at 15:02

1 Answers1

3

IIUC you want zip for this. Here's a simple example taking the sum:

generators = [(1,2), (3,4), (5,6)]
[sum(i) for i in zip(*generators)]

# [9, 12]

Or itertools.zip_longest as @alexis suggests, if the generators could differ in length and you'd like to iterate until the longest one is consumed:

generators = [(1,2), (3,4), (5,6,0)]
[sum(i) for i in zip_longest(*generators, fillvalue=0)]
# [9, 12, 0]
yatu
  • 86,083
  • 12
  • 84
  • 139
  • 1
    Or `itertools.izip_longest`, for maximum robustness. – alexis Feb 13 '19 at 15:01
  • It's not more robust, it's just different. Whether `zip` or `izip_longest` is appropriate is something you need to decide for each use case. (And most of the time, you are zipping lists that have--or are *supposed* to have--the same length.) – chepner Feb 13 '19 at 15:04
  • 1
    Again, it's not more robust. Your use-case determines if (using `[[1,2,3], [4,5]]` as an example) ignoring the `3` from the first list or pairing it with some extra value like `(3, None)` is the *correct* thing to do. – chepner Feb 13 '19 at 15:08