[英]get permutations of dict nested with dicts
Really struggling to find a good solution for this problem.真的很难为这个问题找到一个好的解决方案。
assume I have the following dict:假设我有以下字典:
items = {
"item_name": {
"apple": {"color": ["red", "blue"]},
"banana": {"color": ["yellow", "red"]}
},
"type": ["ripe", "not_ripe"]
}
and I want to generate the following output:我想生成以下 output:
[
{"item_name": "apple", "colors": "red", "type": "ripe"},
{"item_name": "apple", "colors": "blue", "type": "ripe"},
{"item_name": "apple", "colors": "red", "type": "not_ripe"},
{"item_name": "apple", "colors": "blue", "type": "not_ripe"},
{"item_name": "banana", "colors": "yellow", "type": "ripe"},
{"item_name": "banana", "colors": "red", "type": "ripe"},
{"item_name": "banana", "colors": "yellow", "type": "not_ripe"},
{"item_name": "banana", "colors": "red", "type": "not_ripe"},
]
So I want the cartesion product of item_name
x color
x type
, but the possible values for color
are different for each item_name
(possibly overlapping), so it is not sufficient to just permute all the dict keys with itertools.product
as described eg in this question所以我想要
item_name
x color
x type
的笛卡尔积,但是每个item_name
的color
可能值都不同(可能重叠),因此仅使用itertools.product
置换所有 dict 键是不够的,例如在此问题
This is different from the problems I have found on SO, as far as I see it there are question on resolving nested dicts, but only if the sub-elements are lists (not dicts, as it is the case in my question), for example here or here .这与我在 SO 上发现的问题不同,据我所知,存在解决嵌套字典的问题,但前提是子元素是列表(不是字典,因为我的问题就是这种情况),因为此处或此处的示例。
I would really like to show anything that i have tried but so far I canceled each approach for being too complex.我真的很想展示我尝试过的任何东西,但到目前为止我因为太复杂而取消了每种方法。
Is there a straightforward to achieve the desired result?有没有直接达到预期结果的方法? It would also be an option to change the structure of
items
in a way that the logic is preserved.以保留逻辑的方式更改
items
的结构也是一种选择。
Use this.用这个。 I defined a recursive function to get all the combinations from a list of buckets:
我定义了一个递归 function 以从存储桶列表中获取所有组合:
def bucket(lst, depth=0):
for item in lst[0]:
if len(lst) > 1:
for result in bucket(lst[1:], depth+1):
yield [item] + result
else:
yield [item]
items = {
"item_name": {
"apple": {"color": ["red", "blue"]},
"banana": {"color": ["yellow", "red"]}
},
"type": ["ripe", "not_ripe"]
}
lst = []
for item, colours in items['item_name'].items():
combinations = list(bucket([colours['color'], items['type']]))
for colour, ripeness in combinations:
lst.append({'item_name': item, 'color': colour, 'type': ripeness})
print(lst)
Output: Output:
[{'color': 'red', 'item_name': 'apple', 'type': 'ripe'},
{'color': 'red', 'item_name': 'apple', 'type': 'not_ripe'},
{'color': 'blue', 'item_name': 'apple', 'type': 'ripe'},
{'color': 'blue', 'item_name': 'apple', 'type': 'not_ripe'},
{'color': 'yellow', 'item_name': 'banana', 'type': 'ripe'},
{'color': 'yellow', 'item_name': 'banana', 'type': 'not_ripe'},
{'color': 'red', 'item_name': 'banana', 'type': 'ripe'},
{'color': 'red', 'item_name': 'banana', 'type': 'not_ripe'}]
This will work这将起作用
If you want it to look really bad and unreadable you could do this:如果您希望它看起来非常糟糕且难以阅读,您可以这样做:
print([{"item_name": name, "colors": color, "type": typ} for name in list(items["item_name"].keys()) for typ in items["type"] for color in items["item_name"][name]["color"]])
Which is essentially the same as this:这与此基本相同:
def get_combos(items):
names = list(items["item_name"].keys())
types = items["type"]
current = []
for name in names:
for typ in types:
for color in items["item_name"][name]["color"]:
current.append({"item_name": name, "colors": color, "type": typ})
return current
print(get_combos(items))
OUTPUT OUTPUT
[
{'item_name': 'apple', 'colors': 'red', 'type': 'ripe'},
{'item_name': 'apple', 'colors': 'blue', 'type': 'ripe'},
{'item_name': 'apple', 'colors': 'red', 'type': 'not_ripe'},
{'item_name': 'apple', 'colors': 'blue', 'type': 'not_ripe'},
{'item_name': 'banana', 'colors': 'yellow', 'type': 'ripe'},
{'item_name': 'banana', 'colors': 'red', 'type': 'ripe'},
{'item_name': 'banana', 'colors': 'yellow', 'type': 'not_ripe'},
{'item_name': 'banana', 'colors': 'red', 'type': 'not_ripe'}
]
Since each item has unique properties (ie 'colors'), looping over the items is the intuitive solution:由于每个项目都有独特的属性(即“颜色”),循环项目是直观的解决方案:
import itertools
items = {
"item_name": {
"apple": {"color": ["red", "blue"]},
"banana": {"color": ["yellow", "red"]}
},
"type": ["ripe", "not_ripe"]
}
items_product = []
for item, properties in items["item_name"].items():
items_product.extend(
[dict(zip(("type", *properties.keys(), "item_name"), (*values, item)))
for values in itertools.product(items["type"], *properties.values())])
print(items_product)
Horrendous one-liner is also an option:可怕的单线也是一种选择:
items_product = [
comb for item, properties in items["item_name"].items()
for comb in (
dict(
zip(("item_name", "type", *properties.keys()),
(item, *values))
)
for values in itertools.product(items["type"], *properties.values())
)
]
I hope you understand this is a fertile soil for having nightmares.我希望你明白这是做噩梦的沃土。
First, we define the structure of the dictionary you provide and let it is T
.首先,我们定义您提供的字典的结构,并将其设为
T
。 We can find that the value of T
can be a list or a dictionary, but the value type of the dictionary must be T
:我们可以发现
T
的值可以是列表也可以是字典,但是字典的值类型必须是T
:
T = dict[str, dict[str, 'T'] | list[str]]
After the recursive definition of the type is clear, we can easily (maybe not, I'll explain it in my spare time.) use the recursive function to solve it:明确了类型的递归定义后,我们就可以轻松(可能不会,我会在空闲时间解释)使用递归的function来解决它:
from functools import reduce
from operator import ior
from itertools import product
def flat(mapping: T) -> list[dict[str, str]]:
collection = [[{k: vk} | mp for vk, vv in v.items() for mp in flat(vv)]
if isinstance(v, dict)
else [{k: elem} for elem in v]
for k, v in mapping.items()]
return [reduce(ior, mappings, {}) for mappings in product(*collection)]
Test:测试:
>>> items = {
... "item_name": {
... "apple": {"color": ["red", "blue"]},
... "banana": {"color": ["yellow", "red"]}
... },
... "type": ["ripe", "not_ripe"]
... }
>>> from pprint import pp
>>> pp(flat(items))
[{'item_name': 'apple', 'color': 'red', 'type': 'ripe'},
{'item_name': 'apple', 'color': 'red', 'type': 'not_ripe'},
{'item_name': 'apple', 'color': 'blue', 'type': 'ripe'},
{'item_name': 'apple', 'color': 'blue', 'type': 'not_ripe'},
{'item_name': 'banana', 'color': 'yellow', 'type': 'ripe'},
{'item_name': 'banana', 'color': 'yellow', 'type': 'not_ripe'},
{'item_name': 'banana', 'color': 'red', 'type': 'ripe'},
{'item_name': 'banana', 'color': 'red', 'type': 'not_ripe'}]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.