Is there an analogue for this in more-itertools or the standard library?
from typing import Callable, Iterable, Sequence, Tuple, TypeVar
from itertools import tee, filterfalse
T = TypeVar("T")
Predicate = Callable[[T], bool]
T = TypeVar("T")
def group_multiple(items: Iterable[T],
keys: Sequence[Predicate[T]]
) -> Tuple[Iterable[T], ...]:
"""
Returns a tuple of size ``len(keys)`` where each element
of index ``n`` is a iterable that yields values where
``keys[n](next(element))`` is True.
This is useful when grouping elements by attributes that are not
mutually exclusive, meaning that a single element in the iterable
can appear a single time in multiple iterables.
"""
iters = tee(iter(items), len(keys))
return (*(filterfalse(key, iter_) for key, iter_ in zip(keys, iters)),)
With this, one can generate all the vertices for the faces of a unit cube quite easily
# cartesian product
from itertools import product
vx0, vx1, vy0, vy1, vz0, vz1 = group_multiple(
product([0, 1], repeat=3),
(*(lambda point, dim=dim, val=val: point[dim] == val \
# for planes x==0, x==1, y==0, y==1, z==0, z==1
for dim, val in product(range(3), [1, 0])),)
)
[list(iter_) for iter_ in (vx0, vx1, vy0, vy1, vz0, vz1)]
The vertices can later be sorted using scipy.cluster.hierarchy.linkage
if necesary.