Created
May 23, 2017 21:34
-
-
Save carlosasj/2b8f59ce2616faa85ec7713115a0f133 to your computer and use it in GitHub Desktop.
Dynamic Spread-dot Operator in Python
This file contains hidden or 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
''' | |
This function allow you to describe a "path" on the iterator (itr) | |
and then create a generator that yields all elements that match | |
the path. You can use the token "[*]" do describe an iteration over | |
the list. | |
Example: | |
itr = {"foo": { | |
"bar": ["baz", "foz"] | |
}} | |
path = "foo.bar" | |
it will yield: | |
- ["baz", "foz"] | |
(1 item, the list) | |
BUT, for the same itr, if you have the path = "foo.bar[*]", it will yield: | |
- "baz" | |
- "foz" | |
(2 items, it iterates over the list) | |
''' | |
# requirements.txt must include | |
# python-box>=3.0.1 | |
def spread_generator(path: str, itr): | |
if not path: | |
if itr: | |
yield itr | |
raise StopIteration | |
itr = Box(itr) | |
path_list = re.split(r'(\[\*\]\.?)', path, maxsplit=1) | |
path_list = [p for p in path_list if p] | |
path_0 = path_list.pop(0) | |
tmp = eval(f"itr.{path_0}") | |
if not path_list: | |
yield tmp | |
else: | |
path_list.pop(0) # Remove the chunck "[*]" | |
if isinstance(tmp, Box): | |
tmp = tmp.to_dict().values() | |
elif isinstance(tmp, BoxList): | |
tmp = tmp.to_list() | |
new_path = path_list[0] if path_list else None | |
yield from chain.from_iterable( | |
map(lambda x: spread_generator(new_path, x), tmp) | |
) | |
''' | |
An extended example: | |
Given | |
itr = {"foo": [ | |
{"bar": ["bazz", "fazz"]}, | |
{"bar": ["bizz", "fizz"]}, | |
{"bar": ["buzz", "fuzz"]}, | |
] | |
} | |
===== example 1 ===== | |
path = "foo[*].bar" | |
result: | |
- ["bazz", "fazz"] | |
- ["bizz", "fizz"] | |
- ["buzz", "fuzz"] | |
(3 items) | |
===== example 2 ===== | |
path = "foo[*].bar[*]" | |
result: | |
- "bazz" | |
- "fazz" | |
- "bizz" | |
- "fizz" | |
- "buzz" | |
- "fuzz" | |
(6 items) | |
===== example 3 ===== | |
path = "foo[:3].bar" # you can use the list syntax from python | |
result: | |
- ["bazz", "fazz"] | |
- ["bizz", "fizz"] | |
(2 items) | |
===== example 4 ===== | |
path = "foo[*].bar[0]" | |
result: | |
- "bazz" | |
- "bizz" | |
- "buzz" | |
(3 items) | |
''' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment