Skip to content

Instantly share code, notes, and snippets.

@yuchen-xue
Created December 9, 2023 09:55
Show Gist options
  • Save yuchen-xue/27df9dc188d6794114634e500d782334 to your computer and use it in GitHub Desktop.
Save yuchen-xue/27df9dc188d6794114634e500d782334 to your computer and use it in GitHub Desktop.
A generator function that flattens a nested `Mapping` object.
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