Simple generator version, holds the least amount of values possible in memory and calls pred
only once:
from collections import dequefrom typing import Callable, TypeVar, Iterable_T = TypeVar('_T')def iter_split(pred: Callable[[_T], bool], iterable: Iterable[_T]) -> tuple[Iterable[_T], Iterable[_T]]:"""Split an iterable into two iterables based on a predicate. The predicate will only be called once per element. Returns: A tuple of two iterables, the first containing all elements for which the predicate returned True, the second containing all elements for which the predicate returned False.""" iterator = iter(iterable) true_values: deque[_T] = deque() false_values: deque[_T] = deque() def true_generator(): while True: while true_values: yield true_values.popleft() for item in iterator: if pred(item): yield item break false_values.append(item) else: break def false_generator(): while True: while false_values: yield false_values.popleft() for item in iterator: if not pred(item): yield item break true_values.append(item) else: break return true_generator(), false_generator()