Преобразование списка списков в словарь словарей в Python
Я пытаюсь преобразовать список структур данных списков в словарь словарей.
Список определяется следующим образом:
l = [
['PP','Ear-rings', 'Holesovice', 2000],
['PP','Skirts', 'Holesovice', 1000],
['PP','Dresses', 'E-shop', 1500],
['BM','Butterfly', 'Holesovice', 1600]
]
Моя цель состоит в том, чтобы структура словаря была следующей:
#{'PP' : {'Holesovice' : {'Ear-rings' : 2000, 'Skirts' : 1000},
# 'E-shop' : {'Dresses' : 1500}},
# 'BM' : {'Holesovice' : {'Butterfly' : 1600}}
#}
Этот бит кода не возвращает желаемый результат:
labels_d = {}
items_d = {}
shops_d = {}
for index, row in enumerate(l):
items_d[row[1]] = row[3]
shops_d[row[2]] = items_d
labels_d[row[0]] = shops_d
print(labels_d)
Я нашел несколько сообщений, которые касаются преобразования списков в словари здесь и здесь, но я не работал так, как я хочу. Есть ли какой-либо "чистый" способ, как достичь структуры, опубликованной выше?
Ответы
Ответ 1
Использование dict.setdefault(key, {})
- хороший способ приблизиться к созданию вложенных словарей фиксированной глубины.
l = [
['PP','Ear-rings', 'Holesovice', 2000],
['PP','Skirts', 'Holesovice', 1000],
['PP','Dresses', 'E-shop', 1500],
['BM','Butterfly', 'Holesovice', 1600]
]
d = {}
for tag, item, source, qty in l:
d.setdefault(tag, {}).setdefault(source, {})[item] = qty
Выход
{'BM': {'Holesovice': {'Butterfly': 1600}},
'PP': {'E-shop': {'Dresses': 1500},
'Holesovice': {'Ear-rings': 2000, 'Skirts': 1000}}}
Обобщение
Вышеупомянутое решение можно сделать более общим, построив класс вложенного словаря, отбросив требования на фиксированную глубину.
class NestedDict(dict):
def __getitem__(self, item):
if item not in self:
self[item] = NestedDict()
return super().__getitem__(item)
d = NestedDict()
for tag, item, source, qty in l:
d[tag][source][item] = qty
Также обратите внимание, что подход класса создан таким образом, что он создает только объект, если ключ не существует, в то время как метод setdefault
создавал пустой dict
для каждого доступа.
Ответ 2
Вы можете использовать бесконечно вложенный трюк defaultdict
:
from collections import defaultdict
def nested_dict():
return defaultdict(nested_dict)
nd = nested_dict()
for a, b, c, d in l:
nd[a][c][b] = d
Ответ 3
Вы можете использовать collections.defaultdict
и итерации. В этом случае вы можете точно определить вложенный словарь, чтобы отразить вашу структуру данных.
from collections import defaultdict
L = [['PP','Ear-rings', 'Holesovice', 2000],
['PP','Skirts', 'Holesovice', 1000],
['PP','Dresses', 'E-shop', 1500],
['BM','Butterfly', 'Holesovice', 1600]]
d = defaultdict(lambda: defaultdict(lambda: defaultdict(int)))
for code, item, shop, value in L:
d[code][shop][item] = value
Результат
defaultdict({'BM': defaultdict({'Holesovice': defaultdict(int, {'Butterfly': 1600})}),
'PP': defaultdict({'E-shop': defaultdict(int, {'Dresses': 1500}),
'Holesovice': defaultdict(int,
{'Ear-rings': 2000, 'Skirts': 1000})})})
Ответ 4
def toNested1(l):
def addKeyDict(map,key):
if key not in map:
item = map[key] = {}
return item
return map[key]
zz = {}
for a0,a1,a2,a3 in l :
addKeyDict( addKeyDict( zz, a0) , a2 )[a1] = a3
return zz
Ответ 5
Здесь вы найдете довольно простой способ создания нового словаря:
Если элементы в каждой строке списка не соответствуют соответствующей глубине словаря, просто добавьте/добавьте пару ключ-значение в dict.
код:
list = [
['PP','Ear-rings', 'Holesovice', 2000],
['PP','Skirts', 'Holesovice', 1000],
['PP','Dresses', 'E-shop', 1500],
['BM','Butterfly', 'Holesovice', 1600]
]
dicta = {}
for row in list:
if row[0] not in dicta.keys():
dicta[row[0]] = {row[2]:{row[1]:row[3]}}
continue
if row[2] not in dicta[row[0]].keys():
dicta[row[0]][row[2]] = {row[1]:row[3]}
continue
if row[1] not in dicta[row[0]][row[2]].keys():
dicta[row[0]][row[2]][row[1]] = row[3]
print(dicta)
выход:
{'BM': {'Holesovice': {'Butterfly': 1600}},
'PP': {'E-shop': {'Dresses': 1500},
'Holesovice': {'Ear-rings': 2000, 'Skirts': 1000}}}