Комплексный возврат всех возможных комбинаций словаря Python

Я хочу вернуть все возможные комбинации клавиш словаря Python. В моем случае это словарь с двухуровневой иерархией.

Моя первая попытка выглядит как псевдокодовая последовательность циклов for. Это работает, но это уродливо, и становится очень больно, если у меня много данных.

Я хочу выполнить ту же задачу с подходом понимания диктовок.

Вот моя попытка. Используя эту технику, я мог легко получить много — слишком много — циклов for.

dic = {
    'Sex' : {'Man' : 0, 'Woman' : 1}, 
    'Age group' : {'0-14yrs' : 0, '15-25yrs' : 1, '26-35yrs' : 2}
}

for x in range(len(list(dic['Sex'].keys()))):
    for y in range(len(list(dic['Age group'].keys()))):
        sex = list(dic['Sex'].keys())[x]
        age = list(dic['Age group'].keys())[y]
        print(sex,age)


Man 0-14yrs
Man 15-25yrs
Man 26-35yrs
Woman 0-14yrs
Woman 15-25yrs
Woman 26-35yrs

person asl    schedule 21.02.2019    source источник
comment
Вы не создаете словарь. Почему тогда понимание словаря?   -  person Austin    schedule 21.02.2019


Ответы (2)


Я бы использовал itertools.product.

for sex, age in itertools.product(dic['Sex'], dic['Age group']):
    print(sex, age)

product возвращает генератор кортежей, который вы можете делать с тем, что вам нравится.

Для произвольного dict, где вам не обязательно знать ключи или их порядок заранее, я бы сначала пометил каждое значение его ключом.

>>> for t in list(itertools.product(*[[(k, v) for v in dic[k] ] for k in dic])):
...   print(t)
...
(('Age group', '15-25yrs'), ('Sex', 'Woman'))
(('Age group', '15-25yrs'), ('Sex', 'Man'))
(('Age group', '0-14yrs'), ('Sex', 'Woman'))
(('Age group', '0-14yrs'), ('Sex', 'Man'))
(('Age group', '26-35yrs'), ('Sex', 'Woman'))
(('Age group', '26-35yrs'), ('Sex', 'Man'))

Теперь вы, по крайней мере, знаете «тип» каждого значения в соответствующем кортеже; это не зависит от какого-либо конкретного порядка, связанного с исходным dict.

person chepner    schedule 21.02.2019
comment
И чтобы обобщить это в функцию без жестко закодированных ключей, используйте dic.values() в product. - person Nathan; 21.02.2019
comment
@Nathan Проблема с этим в том, что вы не знаете порядок использования ключей. (Если вы не используете Python 3.7 и не знаете исходный порядок вставки ключей в dict и т. д.) - person chepner; 21.02.2019
comment
Справедливо; Я бы либо сказал, что строка документации находится в порядке вставки (в более новых Python), либо, аналогично вашему подходу, вы могли бы вернуть список диктов, таких как {"Age group": "15-25yrs", "Sex": "Woman"}. Возврат словарей, вероятно, лучше, если вы беспокоитесь о порядке ключей, потому что тогда порядок отсутствует. И они всегда могут сделать tuple(dict.values()), если предпочитают кортежи. namedtuple мог бы быть даже лучше, если бы у пользователя были только ключи, действительные как атрибуты, но это большое предположение, которое здесь не выполняется. - person Nathan; 21.02.2019

Если вы хотите, чтобы ваше решение было максимально общим, вы можете сделать что-то вроде этого:

from itertools import product
product(*dic.values())

Это даст вам генератор со следующими значениями:

[('Мужчина', '0-14лет'), ('Мужчина', '15-25лет'), ('Мужчина', '26-35лет'), ('Женщина', '0-14лет'), ( 'Женщина', '15-25лет'), ('Женщина', '26-35лет')]

person Noam Peled    schedule 21.02.2019
comment
В зависимости от того, как был создан dic и какую версию Python вы используете, вы также можете получить [('0-14yrs', 'Man'), ...]. - person chepner; 21.02.2019
comment
Интересно, можете ли вы привести пример для такого случая, и какая версия python выдаст такой вывод? Как вы думаете, поможет ли здесь OrderedDict(dic)? - person Noam Peled; 21.02.2019
comment
Это пример. До Python 3.7 порядок, в котором dic.values() возвращает подзаголовки, был произвольным. В Python 3.7 это гарантированно будет в том порядке, в котором ключи были впервые добавлены в dic, но вы не обязательно знаете, каков этот порядок. - person chepner; 21.02.2019