IterUtils: Iteration Utilities#
- class my.utils.IterUtils.IterUtils#
Utility functions for working with iterators, sequences, mappings, and other containers.
Examples
Every method is reachable through the combined
utfacade:>>> from my import ut >>> ut.partition([1, 2, 3, 4], lambda v: v % 2 == 0) ([1, 3], [2, 4])
I Construction#
- classmethod IterUtils.build(val: V, *functions: Callable[[V], V]) V#
Apply a sequence of functions to a value using reduce.
- Parameters:
val – Initial value.
*functions – Functions to apply in sequence.
- Returns:
Final transformed value after applying all functions.
Examples
Pipe a value through successive transforms:
>>> from my import ut >>> ut.build(' Hi ', str.strip, str.lower) 'hi'
- classmethod IterUtils.map_items(value: MapT[K, V]) list[tuple[K, V]]#
- classmethod IterUtils.map_items(value: object) list[tuple[Any, Any]]
Extract key-value pairs from mapping-like or tuple sequence objects.
- Parameters:
value – Object to extract items from (dict, mapping, or sequence of 2-tuples).
- Returns:
List of (key, value) tuples, or empty list if extraction fails.
Examples
Accept both mappings and pair sequences:
>>> from my import ut >>> ut.map_items({'a': 1, 'b': 2}) [('a', 1), ('b', 2)] >>> ut.map_items([('a', 1), ('b', 2)]) [('a', 1), ('b', 2)]
- classmethod IterUtils.partition(items: Iterable, pred: Callable[[V], bool]) tuple[list[V], list[V]]#
Partition items into two lists based on a predicate.
- Parameters:
items – Iterable to partition.
pred – Predicate function (True items go to second list).
- Returns:
Tuple of (
fails,passes) (NOTE that fails come first!).
Examples
Partition odds from evens:
>>> from my import ut >>> ut.partition([1, 2, 3, 4], lambda x: x % 2 == 0) ([1, 3], [2, 4])
- classmethod IterUtils.multi_partition(items: Iterable, **preds: Callable[[V], object]) dict[str, list[V]]#
Partition items into multiple named buckets based on predicates.
- Parameters:
items – Iterable to partition.
**preds – Named predicates (keys become bucket names).
- Returns:
Dict with predicate names as keys, plus ‘rest’ for unmatched items.
- Raises:
AssertionError – If ‘rest’ is used as a predicate key name.
Examples
Route items into named buckets, with leftovers under ‘rest’:
>>> from my import ut >>> ut.multi_partition(range(6), even=lambda x: x % 2 == 0, big=lambda x: x > 3) {'even': [0, 2, 4], 'big': [5], 'rest': [1, 3]}
- classmethod IterUtils.type_partition(container: Iterable[T0 | T1], t0: type[T0], t1: type[T1]) tuple[list[T0], list[T1]]#
Partition a container into two lists based on type.
- Parameters:
container – Iterable of mixed-type items.
t0 – Type collected into the first list.
t1 – Type collected into the second list.
- Returns:
Tuple of (items of type t0, items of type t1); items of neither type are dropped.
Examples
Separate ints from strings:
>>> from my import ut >>> ut.type_partition([1, 'a', 2, 'b'], int, str) ([1, 2], ['a', 'b'])
- classmethod IterUtils.bucket(items: Iterable, pred: Callable[[T], K]) dict[K, list[T]]#
Group items into buckets based on a key function.
- Parameters:
items – Iterable to bucket.
pred – Function returning bucket key for each item.
- Returns:
Defaultdict mapping bucket keys to lists of items.
Examples
Group words by first letter:
>>> from my import ut >>> dict(ut.bucket(['apple', 'avocado', 'banana'], lambda w: w[0])) {'a': ['apple', 'avocado'], 'b': ['banana']}
II Selection#
- classmethod IterUtils.find(container: ~collections.abc.Sequence, predicate: ~collections.abc.Callable[[V], bool] | V = <class 'bool'>) int#
Find index of first item matching predicate or value.
- Parameters:
container – Sequence to search.
predicate – Predicate function or value to match (default: bool for truthiness).
- Returns:
Index of first match, or -1 if not found.
Examples
Locate by truthiness, predicate, or literal value:
>>> from my import ut >>> ut.find([0, 0, 3, 5]) 2 >>> ut.find(['x', 'y', 'z'], 'y') 1 >>> ut.find([0, 0]) -1
- classmethod IterUtils.find_key(items: ~my.infra.types.MapT, predicate: ~collections.abc.Callable[[V], bool] | V = <class 'bool'>, default: K | None = None) K | None#
Find the first key in a map whose value matches the provided predicate.
- Parameters:
items – Mapping or iterable of (key, value) pairs to search.
predicate – Predicate function or value to match (default: truthiness check).
default – Default value to return if no match found (default: None).
- Returns:
First matching key, or default if none found.
Examples
Find the key of the first matching value:
>>> from my import ut >>> ut.find_key({'a': 0, 'b': 2, 'c': 3}, lambda v: v > 1) 'b' >>> ut.find_key({'a': 0}, lambda v: v > 1, default='n/a') 'n/a'
- classmethod IterUtils.next_in(container: Container, items: Iterable) V | None#
Find first item from iterable that exists in container.
- Parameters:
container – Container to check membership in.
items – Items to check.
- Returns:
First item found in container, or None.
Examples
Take the first item the container admits:
>>> from my import ut >>> ut.next_in({'b', 'c'}, ['a', 'b', 'c']) 'b'
- classmethod IterUtils.condense(items: Iterable[V | False | None], pred: Pred[V] = bool) list[V]#
- classmethod IterUtils.condense(items: Iterable[V], pred: Pred[V] = bool) list[V]
Filter items by predicate, returning list of matches.
- Parameters:
items – Iterable to filter.
pred – Predicate function (default: bool for truthiness).
- Returns:
List of items matching predicate.
Examples
Drop falsy values, or filter by an explicit predicate:
>>> from my import ut >>> ut.condense([0, 1, '', 'x', None]) [1, 'x'] >>> ut.condense([1, 2, 3, 4], lambda x: x % 2) [1, 3]
- classmethod IterUtils.normalize_predicate(pred: Pred) Callable[[P], bool]#
Convert a predicate that may be a value, iterable, or function into a standard function.
- Parameters:
pred – Predicate to normalize (value, iterable, or function).
- Returns:
A one-argument function returning a boolean.
Examples
Turn a container into a membership test, and a value into an equality test:
>>> from my import ut >>> fn = ut.normalize_predicate([1, 2]) >>> fn(1), fn(5) (True, False) >>> eq = ut.normalize_predicate(3) >>> eq(3), eq(4) (True, False)
- classmethod IterUtils.predicate(items: Iterable, *preds: Pred) Iterator#
Filter items by one or more predicates, yielding matches.
- Parameters:
items – Iterable to filter.
*preds – Predicates to apply (value, iterable, or function).
- Yields:
Items satisfying every given predicate.
Examples
Keep only items that pass all predicates:
>>> from my import ut >>> list(ut.predicate([1, 2, 3, 4], lambda x: x > 1, lambda x: x < 4)) [2, 3]
- classmethod IterUtils.map_condense(items: MapT, pred: Pred = <class 'bool'>) Iterator[tuple[K, V]]#
Filter a mapping by a predicate function on values.
- Parameters:
items – Mapping or iterable of (key, value) pairs to filter.
pred – Predicate function applied to values (default: bool for truthiness).
- Yields:
(key, value) tuples where value satisfies the predicate.
Examples
Keep entries with truthy values:
>>> from my import ut >>> list(ut.map_condense({'a': 0, 'b': 2, 'c': ''})) [('b', 2)]
- classmethod IterUtils.get_all(data: dict[K, V], *args: Pred[K], mandatory: bool = True) dict[K, V]#
- classmethod IterUtils.get_all(data: BaseModel | object, *args: Pred[K], mandatory: bool = True) dict[str, Any]
Extract multiple keys from a dictionary or model.
- Parameters:
data – Source of key-value pairs, to be extracted.
*args – Keys or predicates to extract.
mandatory – If True, only return values if all supplied arguments are satisfied/present; otherwise return whatever partial matches were found (default: True).
- Returns:
Dict with requested keys that exist, or {} if
mandatoryand any key is missing.
Examples
All-or-nothing extraction, unless
mandatoryis disabled:>>> from my import ut >>> ut.get_all({'a': 1, 'b': 2, 'c': 3}, 'a', 'b') {'a': 1, 'b': 2} >>> ut.get_all({'a': 1}, 'a', 'z') {} >>> ut.get_all({'a': 1}, 'a', 'z', mandatory=False) {'a': 1}
- classmethod IterUtils.get_any(data: MapT[K, V], *args: Pred[K]) dict[K, V]#
- classmethod IterUtils.get_any(data: BaseModel | object, *args: Pred[K]) dict[str, Any]
Extract multiple keys from a dictionary or model.
Note
Remember, a predicate is:
V | Iterable[V] | Callable[[V], R]. In this case,Ris locked tobool.- Parameters:
data – Source of key-value pairs, to be extracted.
*args – Keys or predicates to extract.
- Returns:
Dict with requested keys that exist.
Examples
Collect whichever keys are present:
>>> from my import ut >>> ut.get_any({'a': 1, 'b': 2}, 'a', 'z') {'a': 1}
- classmethod IterUtils.get_first(data: MapT[K, V], *args: K | Callable[[K], bool], default: V, unique: bool = False) V#
- classmethod IterUtils.get_first(data: MapT[K, V], *args: K | Callable[[K], bool], unique: bool = False) V | None
- classmethod IterUtils.get_first(data: Iterable[V], *args: V | Callable[[V], bool], default: V, unique: bool = False) V
- classmethod IterUtils.get_first(data: Iterable[V], *args: V | Callable[[V], bool], unique: bool = False) V | None
Get value for first matching value from the container.
Note
datamust be a mapping or a live iterator (e.g.iter([...])); despite theIterableoverloads, a plain non-iterator sequence falls through every branch and returns None.- Parameters:
data – Structure to search.
*args – Keys to try in order.
default – Default value if no keys found (default: None).
unique – If True, raise error if multiple keys found (default: False).
- Returns:
Value of first matching key, or default.
- Raises:
ValueError – If unique=True and multiple keys match.
Examples
Match keys by predicate, falling back to a default:
>>> from my import ut >>> ut.get_first({'alpha': 1, 'beta': 2}, lambda k: k.startswith('b')) 2 >>> ut.get_first({'a': 1}, 'z', default=0) 0
- classmethod IterUtils.normalize(data: str | bytes | bytearray | memoryview | IO) str#
- classmethod IterUtils.normalize(data: MapT[K, V]) dict[K, V]
- classmethod IterUtils.normalize(data: Iterable[V] | StructT[V]) list[V]
- classmethod IterUtils.normalize(data: V) V
Normalize the input data into a more workable form for casting.
- Parameters:
data – Value to normalize; containers are normalized recursively.
- Returns:
A str/dict/list-shaped equivalent, with byte-strings decoded and times cast to UTC; atoms (None, types, enums, models, …) pass through untouched.
Examples
Decode byte-strings and rebuild containers:
>>> from my import ut >>> ut.normalize({'a': (1, 2), 'b': b'x'}) {'a': [1, 2], 'b': 'x'}
- classmethod IterUtils.safe(container: MapT[K, V | Mapping[Hashable, Any] | Iterable[tuple[Hashable, Any]] | ItemsView | None], *keys: K) V | None#
Safely access nested map values with multiple keys.
- Parameters:
container – Map to access.
*keys – Sequence of keys to traverse.
- Returns:
Value at nested location if all keys exist, else None.
Examples
Traverse nested keys without raising:
>>> from my import ut >>> ut.safe({'a': {'b': 1}}, 'a', 'b') 1 >>> ut.safe({'a': {'b': 1}}, 'a', 'z') is None True
III Application#
- classmethod IterUtils.val_map(func: Callable[[T0], T1], data: Mapping[K, T0] | Iterable[tuple[K, T0]], drop: bool = False) dict[K, T1]#
- classmethod IterUtils.val_map(func: Callable[[K], T1], data: Iterable[K], drop: bool = False) dict[K, T1]
Map a function over values in a mapping or iterable, returning new dictionary.
- Parameters:
func – Function to apply to each value.
data – Mapping, iterable of (key, value) pairs, or iterable of keys.
drop – If True, drop falsy values from result (default: False).
- Returns:
Dictionary with function applied to values (or to items if data is simple iterable).
Examples
Map over a mapping’s values, or build a dict from bare keys:
>>> from my import ut >>> ut.val_map(str.upper, {'a': 'x', 'b': 'y'}) {'a': 'X', 'b': 'Y'} >>> ut.val_map(len, ['hi', 'there']) {'hi': 2, 'there': 5}
- classmethod IterUtils.attr_map(obj: object, fields: Iterable[str], drop: bool = False) dict[str, Any]#
Extract attributes from object into dictionary.
- Parameters:
obj – Object to extract attributes from.
fields – Attribute names to extract.
drop – If True, drop falsy values and use default=’’ (default: False).
- Returns:
Dict mapping field names to attribute values.
Examples
Snapshot attributes into a dict:
>>> from my import ut >>> ut.attr_map(complex(3, 4), ['real', 'imag']) {'real': 3.0, 'imag': 4.0}
- classmethod IterUtils.apply(functions: Callable[[P], R] | Iterable[Callable[[P], R]], *args: P, **kwargs: P) Iterator#
Apply multiple functions to an item, yielding non-falsy results.
- Parameters:
functions – Functions to apply.
*args – Positional arguments to pass to each function.
**kwargs – Keyword arguments to pass to each function.
- Yields:
Non-falsy results from function applications.
Examples
Fan one input out over several functions:
>>> from my import ut >>> list(ut.apply([str.upper, str.title], 'hi there')) ['HI THERE', 'Hi There']
- classmethod IterUtils.inverse_map(functions: Iterable[Callable[[P], R]], predicate: Callable[[R], Any] | None, *args: P, **kwargs: P) Iterator#
Apply multiple functions to a single set of arguments, returning filtered results.
- Parameters:
functions – Functions to apply.
predicate – Predicate with which to filter results (pass None for plain truthiness).
*args – Positional arguments to pass to each function.
**kwargs – Keyword arguments to pass to each function.
- Yields:
Results for which the predicate holds.
Examples
Apply many functions to one argument list:
>>> from my import ut >>> list(ut.inverse_map([min, max], None, [3, 1, 4])) [1, 4]
- classmethod IterUtils.indexof(iterable: Sequence, *preds: Callable[[T], bool] | T) int#
Return the first index in the given iterable that satisfies the predicate.
- Parameters:
iterable – Sequence to search.
*preds – Plain functions (e.g. lambdas) used as predicates; any other value – including builtin or bound callables – is instead compared by equality.
- Returns:
Index of the first item matching any predicate, or -1 if none match.
Examples
Search by predicate or by literal value:
>>> from my import ut >>> ut.indexof(['a', 'bb', 'ccc'], lambda s: len(s) > 1) 1 >>> ut.indexof(['a', 'bb'], 'bb') 1
- classmethod IterUtils.sorted_insert(array: ~collections.abc.MutableSequence, item: T, key: ~collections.abc.Callable[[T], ~typing.Any] = <function IterUtils.<lambda>>) int#
Insert an item into a sorted sequence, keeping it sorted by
key.- Parameters:
array – A mutable sequence, already sorted ascending by
key. Mutated in place.item – The item to insert.
key – Sort key function (default: the item itself).
- Returns:
The index the item was inserted at.
Examples
Keep a running sorted list without a full re-sort:
>>> from my import ut >>> array = [1, 3, 5] >>> ut.sorted_insert(array, 4) 2 >>> array [1, 3, 4, 5]
- classmethod IterUtils.groupby(iterable: Iterable, key: int | str | Callable[[T], Hashable], drop: bool = False, keys: type[Hashable] | None = None) Iterable[tuple[Hashable, list[T]]]#
Group the items in the given iterable by the given key.
Unlike
itertools.groupby, the input does not need to already be sorted bykey– this sorts internally first, so every group is returned complete and contiguous.The key type is left as the broad
Hashable(rather than inferred through a generic type parameter) becausekey’s three accepted shapes – an int index, an attribute name, or a callable – don’t let a type checker relate the argument to a single concrete key type; narrow the result at the call site if a caller needs more.- Parameters:
iterable – Items to group.
key – An int index (for tuple/sequence items), an attribute name (
str), or a callable extracting the group key from an item.drop – If True, drop items whose key is falsy before grouping.
keys – Unused; reserved for a future explicit key-type annotation/validation.
- Yields:
(key, items)pairs, one per distinct key, each with every matching item.
Examples
Group by an attribute name, dropping items with a falsy key:
>>> from my import ut >>> class Item: ... def __init__(self, tag): ... self.tag = tag >>> items = [Item('x'), Item(''), Item('y'), Item('x')] >>> {k: len(v) for k, v in ut.groupby(items, 'tag', drop=True)} {'x': 2, 'y': 1}
- classmethod IterUtils.locate(seq: Sequence, pred: Callable[[T], bool]) tuple[int, T]#
Return the
(index, item)pair for the first item inseqmatchingpred.- Parameters:
seq – Sequence to search.
pred – Predicate function to apply to each item.
- Returns:
A
(index, item)tuple for the first match.- Raises:
AssertionError – If no item in
seqsatisfiespred.
Examples
>>> from my import ut >>> ut.locate([10, 20, 30], lambda x: x > 15) (1, 20)
IV Execution#
- classmethod IterUtils.repeat_until_complete(func: Callable[[C, V], tuple[int, V]]) Callable#
Decorator to repeatedly apply function until it returns 0 changes.
- Parameters:
func – Function returning (num_changes, transformed_value).
- Returns:
Wrapped function that repeats until num_changes is 0.
Examples
Halve a number until it goes odd, counting the passes:
>>> from my import ut >>> @ut.repeat_until_complete ... def halve_evens(_, n): ... return (1, n // 2) if n % 2 == 0 else (0, n) >>> halve_evens(None, 40) (3, 5)
V Presence#
- classmethod IterUtils.has_all(container: Container, *args: V) bool#
Check if container contains all specified items.
- Parameters:
container – Container to check.
*args – Items that must all be present.
- Returns:
True if all items present, False otherwise or if container empty.
Examples
Require every item:
>>> from my import ut >>> ut.has_all({'a', 'b', 'c'}, 'a', 'b') True >>> ut.has_all({'a'}, 'a', 'z') False
- classmethod IterUtils.has_any(container: Container, *args: V) bool#
Check if container contains any of the specified items.
- Parameters:
container – Container to check.
*args – Items to check for (any match succeeds).
- Returns:
True if any item present, False otherwise or if container empty.
Examples
Any one match suffices:
>>> from my import ut >>> ut.has_any(['a', 'b'], 'b', 'z') True
- classmethod IterUtils.has_only(container: Collection, *args: V) bool#
Check if container contains exactly the specified items, no more no less.
- Parameters:
container – Collection to check.
*args – Items that should comprise the entire collection.
- Returns:
True if container contains exactly these items.
Examples
Exact membership, order-independent:
>>> from my import ut >>> ut.has_only(['b', 'a'], 'a', 'b') True
- classmethod IterUtils.has_none(container: Container, *args: V) bool#
Check if container contains none of the specified items.
- Parameters:
container – Container to check.
*args – Items that must all be absent.
- Returns:
True if no items present, False otherwise.
Examples
Require total absence:
>>> from my import ut >>> ut.has_none({'a'}, 'x', 'y') True
- classmethod IterUtils.all_has_all(containers: Iterable[Container], *args: V) bool#
Check if all containers contain all specified items.
- Parameters:
containers – Containers to check.
*args – Items that must be in all containers.
- Returns:
True if every container has all items, False otherwise or if empty.
Examples
Every container must contain every item:
>>> from my import ut >>> ut.all_has_all([{'a', 'b'}, {'a', 'b', 'c'}], 'a', 'b') True
- classmethod IterUtils.any_has_all(containers: Iterable[Container], *args: V) bool#
Check if any container contains all specified items.
- Parameters:
containers – Containers to check.
*args – Items that must all be in at least one container.
- Returns:
True if at least one container has all items, False otherwise or if empty.
Examples
One container with every item suffices:
>>> from my import ut >>> ut.any_has_all([{'a'}, {'a', 'b'}], 'a', 'b') True
- classmethod IterUtils.all_has_any(containers: Iterable[Container], *args: V) bool#
Check if all containers contain at least one of the specified items.
- Parameters:
containers – Containers to check.
*args – Items (at least one must be in each container).
- Returns:
True if every container has at least one item, False otherwise or if empty.
Examples
Every container needs at least one of the items:
>>> from my import ut >>> ut.all_has_any([{'a'}, {'b'}], 'a', 'b') True
- classmethod IterUtils.any_has_any(containers: Iterable[Container], *args: V) bool#
Check if any container contains any of the specified items.
- Parameters:
containers – Containers to check.
*args – Items to look for.
- Returns:
True if at least one container has at least one item, False otherwise or if empty.
Examples
Any overlap at all suffices:
>>> from my import ut >>> ut.any_has_any([{'x'}, {'y'}], 'y', 'z') True
VI Comparison#
Find longest common prefix of all strings.
- Parameters:
*strings – Strings to compare.
- Returns:
Longest common prefix string.
Examples
Extract the common start:
>>> from my import ut >>> ut.shared_prefix('flowchart', 'flow', 'flower') 'flow'
Find longest common suffix of all strings.
- Parameters:
*strings – Strings to compare.
- Returns:
Longest common suffix string.
Examples
Extract the common ending:
>>> from my import ut >>> ut.shared_suffix('walking', 'running') 'ing'
- classmethod IterUtils.common_elements(lhs: Sequence | set[V], rhs: Sequence | set[V]) list[V]#
Return a version of the first sequence with only values found in the second.
Treats repeated elements according to their counts in each sequence.
- Parameters:
lhs – First sequence or set.
rhs – Second sequence or set.
- Returns:
List of common elements. For sequences, includes duplicates.
Examples
Duplicates survive only as often as both sides carry them:
>>> from my import ut >>> ut.common_elements([9, 1, 3, 9, 9], [1, 9, 9]) [9, 1, 9]
- classmethod IterUtils.exclusive_elements(lhs: S, rhs: Iterable) S#
Return a version of the first sequence with the second’s values subtracted from it.
The complement of
common_elements(): an ordered multiset difference, where each occurrence inrhscancels exactly one matching occurrence inlhs.- Parameters:
lhs – First sequence.
rhs – Iterable of values to exclude, one occurrence at a time.
- Returns:
A sequence of the same type as
lhs, containing only unexcluded occurrences.
Examples
Subtract per-occurrence – one of the three nines survives:
>>> from my import ut >>> ut.exclusive_elements([9, 1, 3, 9, 9], [1, 9, 9]) [3, 9]
VII Modification#
- classmethod IterUtils.drop_at(data: Sequence, mask: Iterable[int]) list[V]#
Remove elements at specified indices from sequence.
- Parameters:
data – Sequence to filter.
mask – Indices to drop.
- Returns:
List with elements at masked indices removed.
Examples
Remove by index:
>>> from my import ut >>> ut.drop_at(['a', 'b', 'c', 'd'], [1, 3]) ['a', 'c']
- classmethod IterUtils.drop_duplicates(data: MutableSequence) None#
Remove duplicate elements from a list, preserving order.
- Parameters:
data – Mutable sequence to deduplicate in place.
Examples
Deduplicate a list in place:
>>> from my import ut >>> items = [1, 2, 1, 3, 2] >>> ut.drop_duplicates(items) >>> items [1, 2, 3]