recorrer - lista de diccionarios python
Conversión de listas de listas en un diccionario de diccionarios en Python (5)
Estoy intentando convertir una lista de estructura de datos de listas en un diccionario de diccionarios.
La lista se define de la siguiente manera:
l = [
[''PP'',''Ear-rings'', ''Holesovice'', 2000],
[''PP'',''Skirts'', ''Holesovice'', 1000],
[''PP'',''Dresses'', ''E-shop'', 1500],
[''BM'',''Butterfly'', ''Holesovice'', 1600]
]
Mi objetivo es tener la estructura del diccionario de la siguiente manera:
#{''PP'' : {''Holesovice'' : {''Ear-rings'' : 2000, ''Skirts'' : 1000},
# ''E-shop'' : {''Dresses'' : 1500}},
# ''BM'' : {''Holesovice'' : {''Butterfly'' : 1600}}
#}
Este bit de código no devuelve la salida deseada:
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)
Encontré algunas publicaciones que tratan sobre la conversión de listas a diccionarios here y here pero no hice que funcionara como quería. ¿Hay alguna forma "limpia" de cómo lograr la estructura publicada anteriormente?
Aquí publicamos una forma bastante sencilla de componer un nuevo diccionario:
Si los elementos en cada fila de la lista no están en la profundidad correspondiente del diccionario, simplemente agregue / agregue el par clave-valor al dict.
código:
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)
salida:
{''BM'': {''Holesovice'': {''Butterfly'': 1600}},
''PP'': {''E-shop'': {''Dresses'': 1500},
''Holesovice'': {''Ear-rings'': 2000, ''Skirts'': 1000}}}
El uso de dict.setdefault(key, {})
es una buena manera de abordar la creación de diccionarios anidados de profundidad fija.
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
Salida
{''BM'': {''Holesovice'': {''Butterfly'': 1600}},
''PP'': {''E-shop'': {''Dresses'': 1500},
''Holesovice'': {''Ear-rings'': 2000, ''Skirts'': 1000}}}
Generalización
La solución anterior se puede hacer más general al construir una clase de diccionario anidado, eliminando los requisitos para tener una profundidad fija.
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
También tenga en cuenta que el enfoque de clase se crea, por lo que solo crea un objeto si la clave no existe, mientras que el enfoque setdefault
creó un dict
vacío en cada acceso.
Puede utilizar collections.defaultdict
y iterar. En este caso, puede definir con precisión un diccionario anidado para reflejar su estructura de datos.
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
Resultado
defaultdict({''BM'': defaultdict({''Holesovice'': defaultdict(int, {''Butterfly'': 1600})}),
''PP'': defaultdict({''E-shop'': defaultdict(int, {''Dresses'': 1500}),
''Holesovice'': defaultdict(int,
{''Ear-rings'': 2000, ''Skirts'': 1000})})})
Puedes usar el truco defaultdict
infinitamente anidado:
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
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