Skip to content

Instantly share code, notes, and snippets.

@rendarz
Last active December 5, 2020 02:37
Show Gist options
  • Save rendarz/cc2c99cdce4dc56d2f17e74342bfb241 to your computer and use it in GitHub Desktop.
Save rendarz/cc2c99cdce4dc56d2f17e74342bfb241 to your computer and use it in GitHub Desktop.
Consume multiple iterators, filling each when exhausted with the last value they produced.
def zip_longest_last(*args):
"""Consume multiple iterators, filling each when exhausted with the last value they produced."""
line = []
# CREATE a list of iterators of iterable objects passed as args.
iters = [iter(it) for it in args]
active = len(iters)
lasts = [None]*active
# CREATE a generator that yields the last item forever.
def take_last(index):
while True:
yield lasts[index]
# MAIN LOOP.
while True:
# FOREACH iterator in the list.
for n, it in enumerate(iters):
try:
# GET the value from the iterator.
value = next(it)
# CHECK if there are no elements left into the iterator.
except StopIteration:
# REPLACE the exhausted iterator with the generator
# that yields forever the last element.
iters[n] = take_last(n)
# SET that last element to the value we have to yield.
value = lasts[n]
# DECREASE active iterators.
active -= 1
if active == 0:
# EXIT if there are no more active iterators.
return
else:
# SAVE the last element of this iterator.
lasts[n] = value
# ADD this element value to the current line of elements
# we will yield.
line.append(value)
# YIELD the line of elements as a tuple.
yield tuple(line)
# CLEAR the line to make room for the next line.
line = []
@rendarz
Copy link
Author

rendarz commented Dec 4, 2020

Thanks! 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment