Как развернуть словарь списков Python, основанный на "парах ключ-значение"?

У меня есть алгоритмическая проблема с использованием словаря списков Python3.x, хотя, возможно, более подходящей является другая структура данных.

Допустим, у меня есть следующий словарь Python:

dict1 = {1:[4, 12, 22], 2:[4, 5, 13, 23], 3:[7, 15, 25]}

Ключ 1 ассоциировать со значением [4, 12, 22] означает, что 1 "связан с" 4. 1 также связан с 12, а 1 связан с 22. Кроме того, 2 связан с 4, 2 связан с 5, 2 связан с 13 и 1 связан с 23 и т. д.

Мой вопрос, для этого небольшого примера, как мне "развернуть" этот словарь так, чтобы каждый элемент списка значений кодировал эту "ассоциацию"?

То есть конечный результат должен быть:

intended_dict = {1:[4, 12, 22], 2:[4, 5, 13, 23], 3:[7, 15, 25], 
                     4:[1, 2], 5:[2], 12:[1], 13:[2], 15:[3], 22:[1], 23:[2], 25:[3]}

потому что 4 ассоциируется с 1, 4 ассоциируется с 2, 5 ассоциируется с 2 и т. д.

Есть ли способ "развернуть" подобные словари?

Как бы это масштабировалось до гораздо большего словаря с большими списками с миллионами целых чисел?

Возможно, другая структура данных будет более эффективной, особенно с гораздо большими списками?

РЕДАКТИРОВАТЬ: Учитывая размер фактического словаря, с которым я работаю (а не тот, который выложен выше), решение должно быть максимально эффективным с точки зрения памяти и производительности.

4 ответа

Простой лайнер:

newdict={v:[i for i in dict1.keys() if v in dict1[i]] for k,v in dict1.items() for v in v}
print(newdict)

Выход:

{4: [1, 2], 12: [1], 22: [1], 5: [2], 13: [2], 23: [2], 7: [3], 15: [3], 25: [3]}

Чтобы объединить их:

print({**dict1,**newdict})

Одним из способов является использование collections.defaultdict

from collections import defaultdict
dict1 = {1:[4, 12, 22], 2:[4, 5, 13, 23], 3:[7, 15, 25]}
d_dict = defaultdict(list)

for k,l in dict1.items():
    for v in l:
        d_dict[v].append(k)

intended_dict = {**dict1, **d_dict}
print (intended_dict)
#{1: [4, 12, 22], 2: [4, 5, 13, 23], 3: [7, 15, 25], 4: [1, 2], 12: [1], 22: [1], 5: [2], 13: [2], 23: [2], 7: [3], 15: [3], 25: [3]}

Следующее будет делать:

intended_dict = dict1.copy()
for k, v in dict1.items():
    for i in v:
        intended_dict.setdefault(i, []).append(k)

Вы в основном пытаетесь хранить отношения. Об этом есть целое поле - они хранятся в реляционных базах данных, которые содержат таблицы. В Python было бы более естественно сделать это в виде списка из 2-х списков - или, поскольку ваше отношение симметрично и порядок не имеет значения, в виде списка из 2-х множеств. Еще лучшее решение, хотя это pandas который является каноническим пакетом для создания таблиц в Python.

Пока вот как превратить вашу оригинальную вещь в pandas объект, а затем превратить это в вашу фиксированную вещь для включения симметрии.

import pandas as pd

dict1 = {1:[4, 12, 22], 2:[4, 5, 13, 23], 3:[7, 15, 25]}

relations = pd.DataFrame(
    [[key, value] for key, values in dict1.items() for value in values]
)

print(relations)

Out:
   0   1
0  1   4
1  1  12
2  1  22
3  2   4
4  2   5
5  2  13
6  2  23
7  3   7
8  3  15
9  3  25

result = {
    **{key: list(values) for key, values in relations.groupby(0)[1]},
    **{key: list(values) for key, values in relations.groupby(1)[0]}
}

print(result)

Out:
{1: [4, 12, 22],
 2: [4, 5, 13, 23],
 3: [7, 15, 25],
 4: [1, 2],
 5: [2],
 7: [3],
 12: [1],
 13: [2],
 15: [3],
 22: [1],
 23: [2],
 25: [3]}
Другие вопросы по тегам