Как перебрать словарь списков и связать каждую итерацию с элементом из всех ключей?

Мне нужно перебрать словарь списков, не зная, сколько списков будет в словаре, но все же связывать каждое значение списка с любым другим значением списка, полученным из другого ключа в словаре (если существует другой). У меня есть следующий код:

def loop_rec(codes, currentcode={}):
    if len(codes.keys())>1:
        for key in sorted(codes):
            codespop = dict(codes)
            loop = codespop.pop(key)
            for x in loop:
                currentcode[key]=x
                loop_rec(codespop,currentcode)
            break
    else:
        for key in codes.keys():
            loop = codes[key]
            for x in loop:
                currentcode[key]=x
                print currentcode

Так что, если у меня есть следующий словарь:

codes = {"coarse":range(4),"fine":range(2)}

Я получаю этот результат:

>>> loop_rec(codes)
{'fine': 0, 'coarse': 0}
{'fine': 1, 'coarse': 0}
{'fine': 0, 'coarse': 1}
{'fine': 1, 'coarse': 1}
{'fine': 0, 'coarse': 2}
{'fine': 1, 'coarse': 2}
{'fine': 0, 'coarse': 3}
{'fine': 1, 'coarse': 3}

Это метод грубой силы, и он хотел бы сделать это более "пифоническим". Я много раз искал что-то эквивалентное, но большинство методов не приводит к тому, что грубые и точные значения находятся вместе для каждой итерации. Также предпочел бы, чтобы это сначала проходило по грубому, но отсортированная команда не работает.

РЕДАКТИРОВАТЬ: Просто понял, что отсортированная команда работает, распечатка просто не отсортирована. Мне все равно, если это напечатано по порядку.

1 ответ

Решение

Если я правильно понимаю ваш вопрос, вы хотите взять декартово произведение всех списков, которые являются значениями dict. Ты можешь использовать itertools.product чтобы сделать это.

import itertools
def dict_product(d):
    list_of_dicts = []
    for values in itertools.product(*d.values()):
        item = dict(zip(d.keys(),values))
        list_of_dicts.append(item)
    return list_of_dicts


codes = {"coarse":range(4),"fine":range(2),"zesty":range(3)}
for item in dict_product(codes):
    print(item)

Результат:

{'zesty': 0, 'fine': 0, 'coarse': 0}
{'zesty': 0, 'fine': 0, 'coarse': 1}
{'zesty': 0, 'fine': 0, 'coarse': 2}
{'zesty': 0, 'fine': 0, 'coarse': 3}
{'zesty': 0, 'fine': 1, 'coarse': 0}
{'zesty': 0, 'fine': 1, 'coarse': 1}
{'zesty': 0, 'fine': 1, 'coarse': 2}
{'zesty': 0, 'fine': 1, 'coarse': 3}
{'zesty': 1, 'fine': 0, 'coarse': 0}
{'zesty': 1, 'fine': 0, 'coarse': 1}
{'zesty': 1, 'fine': 0, 'coarse': 2}
{'zesty': 1, 'fine': 0, 'coarse': 3}
{'zesty': 1, 'fine': 1, 'coarse': 0}
{'zesty': 1, 'fine': 1, 'coarse': 1}
{'zesty': 1, 'fine': 1, 'coarse': 2}
{'zesty': 1, 'fine': 1, 'coarse': 3}
{'zesty': 2, 'fine': 0, 'coarse': 0}
{'zesty': 2, 'fine': 0, 'coarse': 1}
{'zesty': 2, 'fine': 0, 'coarse': 2}
{'zesty': 2, 'fine': 0, 'coarse': 3}
{'zesty': 2, 'fine': 1, 'coarse': 0}
{'zesty': 2, 'fine': 1, 'coarse': 1}
{'zesty': 2, 'fine': 1, 'coarse': 2}
{'zesty': 2, 'fine': 1, 'coarse': 3}

В этом примере порядок итераций является грубым-точным, но это поведение не гарантируется. В CPython 3.6 и выше словари упорядочены, но это деталь реализации и может измениться в будущем.

Другие вопросы по тегам