# https://stackoverflow.com/a/75409015/1468366

import collections.abc
import itertools
import math
import typing

T = typing.TypeVar('T')
def combination_batches(
        seq: collections.abc.Sequence[T],
        r: int,
        max_batch_size: int,
        prefix: tuple[T, ...] = ()
    ) -> collections.abc.Iterator[collections.abc.Iterator[tuple[T, ...]]]:
    """Compute batches of combinations.

    Each yielded value is itself a generator over some of the combinations.
    Taken together they produce all the combinations.

    Args:
      seq: The sequence of elements to choose from.
      r: The number of elements to include in each combination.
      max_batch_size: How many elements each returned iterator
        is allowed to iterate over.
      prefix: Used during recursive calls, prepended to each returned tuple.
    Yields: generators which each generate a subset of all the combinations,
      in a way that generators together yield every combination exactly once.
    """
    if math.comb(len(seq), r) > max_batch_size:
        # One option: first element taken.
        yield from combination_batches(
            seq[1:], r - 1, max_batch_size, prefix + (seq[0],))
        # Other option: first element not taken.
        yield from combination_batches(
            seq[1:], r, max_batch_size, prefix)
        return
    yield (prefix + i for i in itertools.combinations(seq, r))

for i in combination_batches("abcdefg", 3, 5):
    print("---")
    for j in i:
        print("".join(j))
