Reputation: 5549
I have a lazy chain of generators. I would like to chain a generator onto the output of these, but only onto a "range" subset of the output. Specifically, I would like to skip some rows:
def foo():
yield "pickles"
yield from iter(range(4))
def bar(foo_numbers):
yield from (5*num for num in foo_numbers)
# how to construct foo_bar from `foo` and `bar`?
assert foo_bar == ['pickles', 0, 5, 10, 15]
Notice that the output foo_bar
can be obtained from foo
followed by bar
, except bar
should only apply to the first through nth element of the output of foo
(skipping the zeroth element). Is there an easy way to have my generators skip n
elements?
Upvotes: -1
Views: 37
Reputation: 110591
The important thing to know is that you can't simply "skip" a generator body execution: it will run whatever code it needs to in order to create its value
The option to do things like what you want are to wrap the generators into other generators that would ignore the unwanted values.
Itertools calls dropwhile
and takewhile
themselves are based on this - and it would be possible to compose dropwhile
, takewhile
, enumerate
and an external generator expression to constrain the values to a given range.
But it is easier and more readable to simply write a generator which takes the original generator and the wanted (or unwanted) indices - and ignores the values that won't be used.
def gen_slicer(generator, wanted_indices):
for index, item in enumerate(generator):
if index in wanted_indices:
yield item
def foo(foo_numbers):
...
...
foo_bar = list(*gen_slicer(foo, {0, 1}), *bar((1, 2, 3))
Upvotes: 0