Skip to content

Instantly share code, notes, and snippets.

@carlosasj
Created May 23, 2017 21:34
Show Gist options
  • Save carlosasj/2b8f59ce2616faa85ec7713115a0f133 to your computer and use it in GitHub Desktop.
Save carlosasj/2b8f59ce2616faa85ec7713115a0f133 to your computer and use it in GitHub Desktop.
Dynamic Spread-dot Operator in Python
'''
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