The code below is from the book "Functional Python Programming, Steven F. Lott" however I can't handle the exception and run the code as expected.
How can I handle the "RuntimeError: generator raised StopIteration"?
Note: I tried googling and read all the results I found from stackoverflow.
Thanks.
from typing import Callable, Iterable, Tuple, Iterator, Any
def group_by_iter(n: int, items: Iterator) -> Iterator[Tuple]:
"""
.>>> list( group_by_iter( 7, filter( lambda x: x%3==0 or x%5==0, range(1,50) ) ) )
[(3, 5, 6, 9, 10, 12, 15), (18, 20, 21, 24, 25, 27, 30), (33, 35, 36, 39, 40, 42, 45), (48,)]
"""
row = tuple(next(items) for i in range(n))
while row:
yield row
row = tuple( next(items) for i in range(n) )
print( list( group_by_iter( 7, filter( lambda x: x%3==0 or x%5==0, range(1,50) ) ) ) )
CodePudding user response:
The built-in next() function can take a second argument which is the default value returned when the iterator is exhausted. You could exploit this functionality to avoid the StopIteration
error by returning None
by default and filtering it from the result.
Change tuple(next(items) for _ in range(n))
to tuple(e for e in [next(items, None) for _ in range(n)] if e is not None)
and the final tuple will be generated cleanly.
from typing import Callable, Iterable, Tuple, Iterator, Any
def group_by_iter(n: int, items: Iterator) -> Iterator[Tuple]:
"""
.>>> list( group_by_iter( 7, filter( lambda x: x%3==0 or x%5==0, range(1,50) ) ) )
[(3, 5, 6, 9, 10, 12, 15), (18, 20, 21, 24, 25, 27, 30), (33, 35, 36, 39, 40, 42, 45), (48,)]
"""
row = tuple(next(items) for _ in range(n))
while row:
yield row
row = tuple(e for e in [next(items, None) for _ in range(n)] if e is not None)
print( list( group_by_iter( 7, filter( lambda x: x%3==0 or x%5==0, range(1,50) ) ) ) )
Output:
[(3, 5, 6, 9, 10, 12, 15), (18, 20, 21, 24, 25, 27, 30), (33, 35, 36, 39, 40, 42, 45), (48,)]