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:
[
{"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 e.g. in this question
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.
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.
Since each item has unique properties (i.e. '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.