Created
December 9, 2023 09:55
-
-
Save yuchen-xue/27df9dc188d6794114634e500d782334 to your computer and use it in GitHub Desktop.
A generator function that flattens a nested `Mapping` object.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from typing import Any, TypeAlias, TypeVar, Union | |
from collections.abc import MutableSequence, Iterable, Mapping, Iterator | |
import copy | |
MS = TypeVar("MS", bound=MutableSequence) | |
Nested: TypeAlias = Mapping[Any, Union[Iterable, "Nested"]] | |
def nested_mapping_serializer( | |
data: Nested, | |
pattern: MS, | |
_depth: int = 0, | |
) -> Iterator[MS]: | |
""" | |
A generator function that flattens a nested `Mapping` object. | |
For each sequential data structure inside the given nested object, | |
the funciton yields a sequential representation containing all of its outer keys, | |
which matches the given pattern (an intialized mutable sequence). | |
Example: | |
``` | |
>>> d = {"Key": {"Nested": {"Items": ["item_1", "item_2", "item_3"]}}} | |
>>> pattern = [None, None, None, None] | |
>>> serializer = nested_mapping_serializer(d, pattern) | |
>>> next(serializer) | |
['Key', 'Nested', 'Items', 'item_1'] | |
>>> next(serializer) | |
['Key', 'Nested', 'Items', 'item_2'] | |
>>> next(serializer) | |
['Key', 'Nested', 'Items', 'item_3'] | |
``` | |
Args: | |
data (Nested): | |
Target nested object. | |
pattern (MS): | |
An intialized mutable sequence | |
which regulates the format of the output. | |
_depth (int, optional): | |
**Private argument! NEVER pass value from outside!** | |
Depth of `data` traversal. Defaults to 0. | |
Yields: | |
Iterator[MS]: | |
A sequential representation satisfying the given patter. | |
""" | |
for k, v in data.items(): | |
pattern[_depth] = k | |
# Increse the depth whenever the function traverse into a `Mapping` object | |
_depth += 1 | |
# If `v` is another `Mapping` object, dig into `v` | |
if isinstance(v, Mapping): | |
yield from nested_mapping_serializer(v, pattern, _depth) | |
# If `v` is of `Iterable` type, traverse this value | |
elif isinstance(v, Iterable): | |
for i in v: | |
pattern[_depth] = i | |
# Yield one serialized result | |
yield copy.copy(pattern) | |
# Decrese the depth whenever the function has finished traversing the `Mapping` object | |
_depth -= 1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment