Как развернуть словарь списков 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]}