Это простой вопрос, но меня смущает поведение collections.defaultdict. Это поможет мне узнать, как это работает.

Этот вопрос является экстраполяцией этого полезного вопроса: Как объединить список несколько словарей в словарь списков?

Допустим, теперь у меня есть список списков словарей. Я хочу объединить словари, как описано в приведенном выше вопросе:

list_of_dictionaries2 = [[{0:3523, 1:3524, 2:3540, 4:3541, 5:3542}, 
    {0:7245, 1:7246, 2:7247, 3:7248, 5:7249, 6:7250},
    {1:20898, 2:20899, 3:20900, 4:20901, 5:20902}], [{0:3, 1:4, 2:5, 3:6}]]

Предполагаемый ответ таков:

correct2 = [[{0:[3523, 7245], 1:[3524, 7246, 20898], 2:[3540, 7247, 20899], 
            3:[7248, 20900], 4:[3541, 20901], 5:[3542, 7249, 20902], 6:[7250]}], 
            [{0:3, 1:4, 2:5, 3:6}]]

Ранее для одного списка словарей мы решили эту проблему, создав пустой словарь со значениями по умолчанию в виде списков, то есть мы использовали collections.defaultdict(list).

Учитывая, что этот случай представляет собой список списков, я подумал, что решением для другого цикла будет добавление словарей в пустой список:

from collections import defaultdict
correct2 = defaultdict(list)

empty = []

for smaller_list in list_of_dictionaries2:
    for d in smaller_list:
        for k,v in d.items():
            correct2[k].append(v)
    empty.append(correct2)

Это очень неправильно.

>>> print(empty)
[defaultdict(<class 'list'>, {0: [3523, 7245, 3], 1: [3524, 7246, 20898, 4], 
2: [3540, 7247, 20899, 5], 4: [3541, 20901], 5: [3542, 7249, 20902], 
3: [7248, 20900, 6], 6: [7250]}), defaultdict(<class 'list'>, 
{0: [3523, 7245, 3], 1: [3524, 7246, 20898, 4], 2: [3540, 7247, 20899, 5], 
4: [3541, 20901], 5: [3542, 7249, 20902], 3: [7248, 20900, 6], 6: [7250]})]

Похоже, что все словари были объединены. И есть две копии. Это не то, что я хочу.

Как мне сделать это для каждого отдельного списка, как указано выше? Где я ошибаюсь в своем понимании?

1
ShanZhengYang 8 Окт 2018 в 05:35

2 ответа

Лучший ответ

На самом деле у вас нет списка словарей, но есть список списков словарей, и вы пытаетесь объединить словари в подсписки, поэтому вы должны инициализировать defaultdict внутри цикла, который выполняет итерацию основной список:

empty = []
for smaller_list in list_of_dictionaries2:
    correct2 = defaultdict(list)
    for d in smaller_list:
        for k,v in d.items():
            correct2[k].append(v)
    empty.append(correct2)

empty станет:

[defaultdict(<class 'list'>, {0: [3523, 7245], 1: [3524, 7246, 20898], 2: [3540, 7247, 20899], 4: [3541, 20901], 5: [3542, 7249, 20902], 3: [7248, 20900], 6: [7250]}), defaultdict(<class 'list'>, {0: [3], 1: [4], 2: [5], 3: [6]})]

Обратите внимание, что ожидаемый результат для второго слияния defaultdict неверен, поскольку значением каждого ключа должен быть список после слияния. Также список списков словаря должен стать списком defaultdict списков после слияния, а не списком списков defaultdict списков.

2
blhsing 8 Окт 2018 в 02:55

Вы должны инициализировать correct2 каждый цикл следующим образом

for smaller_list in list_of_dictionaries2:
    correct2 = defaultdict(list)
    for d in smaller_list:
        for k, v in d.items():
            correct2[k].append(v)
    empty.append(correct2)

Выход будет

[defaultdict(<class 'list'>, {0: [3523, 7245], 1: [3524, 7246, 20898],
2: [3540, 7247, 20899], 4: [3541, 20901], 5: [3542, 7249, 20902], 
3: [7248, 20900], 6: [7250]}), 
defaultdict(<class 'list'>, {0: [3],1: [4], 2: [5], 3: [6]})]

Обратите внимание, что defaultdict является изменяемым объектом

1
Kr.98 8 Окт 2018 в 02:58