Декартово произведение словаря списков
Я пытаюсь написать некоторый код, чтобы проверить декартово произведение пучка входных параметров.
Я посмотрел itertools
, но его функция product
не совсем то, что я хочу. Есть ли простой очевидный способ взять словарь с произвольным количеством ключей и произвольное количество элементов в каждом значении, а затем получить словарь со следующей перестановкой?
Input:
options = {"number": [1,2,3], "color": ["orange","blue"] }
print list( my_product(options) )
Пример вывода:
[ {"number": 1, "color": "orange"},
{"number": 1, "color": "blue"},
{"number": 2, "color": "orange"},
{"number": 2, "color": "blue"},
{"number": 3, "color": "orange"},
{"number": 3, "color": "blue"}
]
Ответы
Ответ 1
Хорошо, спасибо @dfan за то, что он сказал мне, что искал не то место. У меня есть это сейчас:
from itertools import product
def my_product(inp):
return (dict(zip(inp.keys(), values)) for x in product(*inp.values())
EDIT: после многих лет опыта Python я считаю, что лучшим решением является принятие kwargs
а не словарь входов; стиль вызова более itertools.product
на itertools.product
оригинала itertools.product
. Также я думаю, что писать функцию генератора, а не функцию, возвращающую выражение генератора, делает код более понятным. Так:
def product_dict(**kwargs):
keys = kwargs.keys()
vals = kwargs.values()
for instance in itertools.product(*vals):
yield dict(zip(keys, instance))
и если вам нужно передать в dict, list(product_dict(**mydict))
. Единственное заметное изменение, использующее kwargs
а не произвольный класс ввода, заключается в том, что он не позволяет упорядочивать ключи/значения, по крайней мере до Python 3.6.
Ответ 2
версия Python 3 ответ Seth.
import itertools
def dict_product(dicts):
"""
>>> list(dict_product(dict(number=[1,2], character='ab')))
[{'character': 'a', 'number': 1},
{'character': 'a', 'number': 2},
{'character': 'b', 'number': 1},
{'character': 'b', 'number': 2}]
"""
return (dict(zip(dicts, x)) for x in itertools.product(*dicts.values()))
Ответ 3
Кстати, это не перестановка. Перестановка - это перегруппировка списка. Это перечисление возможных выборов из списков.
Изменить: помня, что он был назван декартовым произведением, я придумал следующее:
import itertools
options = {"number": [1,2,3], "color": ["orange","blue"] }
product = [x for x in apply(itertools.product, options.values())]
print [dict(zip(options.keys(), p)) for p in product]
Ответ 4
# I would like to do
keys,values = options.keys(), options.values()
# but I am not sure that the keys and values would always
# be returned in the same relative order. Comments?
keys = []
values = []
for k,v in options.iteritems():
keys.append(k)
values.append(v)
import itertools
opts = [dict(zip(keys,items)) for items in itertools.product(*values)]
приводит к
opts = [
{'color': 'orange', 'number': 1},
{'color': 'orange', 'number': 2},
{'color': 'orange', 'number': 3},
{'color': 'blue', 'number': 1},
{'color': 'blue', 'number': 2},
{'color': 'blue', 'number': 3}
]