Декартово произведение словаря списков - PullRequest
48 голосов
/ 08 марта 2011

Я пытаюсь написать некоторый код, чтобы проверить декартово произведение множества входных параметров.

Я смотрел на itertools, но его функция product не совсем то, что я хочу. Есть ли простой очевидный способ взять словарь с произвольным числом ключей и произвольным числом элементов в каждом значении, а затем получить словарь со следующей перестановкой?

Введите:

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"}
]

Ответы [ 4 ]

46 голосов
/ 08 марта 2011

Хорошо, спасибо @dfan за сообщение, что я искал не в том месте.Теперь я понял:

from itertools import product
def my_product(inp):
    return (dict(zip(inp.keys(), values)) for values in product(*inp.values())

РЕДАКТИРОВАТЬ : после многолетнего опыта работы с Python, я думаю, что лучшее решение - принять kwargs вместо словаря входных данных;стиль звонка больше похож на стиль оригинала itertools.product.Также я думаю, что написание функции генератора, а не функции, которая возвращает выражение генератора, делает код более понятным.Итак:

def product_dict(**kwargs):
    keys = kwargs.keys()
    vals = kwargs.values()
    for instance in itertools.product(*vals):
        yield dict(zip(keys, instance))

и если вам нужно передать в диктанте, list(product_dict(**mydict)).Одно заметное изменение, использующее kwargs вместо произвольного входного класса, заключается в том, что он предотвращает упорядочение ключей / значений, по крайней мере, до Python 3.6.

16 голосов
/ 16 ноября 2016

Python 3 версия ответ Сета .

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()))
6 голосов
/ 08 марта 2011

Кстати, это не перестановка. Перестановка - это перестановка списка. Это перечень возможных выборов из списков.

Редактировать: вспомнив, что это называлось декартовым произведением, я придумал это:

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]
2 голосов
/ 08 марта 2011
# 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}
]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...