Converting list of lists into a dictionary of dictionaries in Python
I am trying to convert a list of lists data structure to a dictionary of dictionaries.
The list is defined as follows:
l = [
['PP','Ear-rings', 'Holesovice', 2000],
['PP','Skirts', 'Holesovice', 1000],
['PP','Dresses', 'E-shop', 1500],
['BM','Butterfly', 'Holesovice', 1600]
]
My aim is to have the dictionary structure as follows:
#{'PP' : {'Holesovice' : {'Ear-rings' : 2000, 'Skirts' : 1000},
# 'E-shop' : {'Dresses' : 1500}},
# 'BM' : {'Holesovice' : {'Butterfly' : 1600}}
#}
This bit of code does not return desired output:
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)
I found some posts that deal with converting lists to dictionaries here and here but I did not make it work the way I want. Is there any 'clean' way how to achieve the structure posted above?
Using dict.setdefault(key, {}) is a good way to approach the creation of nested dictionaries of fixed depth.
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
Output
{'BM': {'Holesovice': {'Butterfly': 1600}},
'PP': {'E-shop': {'Dresses': 1500},
'Holesovice': {'Ear-rings': 2000, 'Skirts': 1000}}}
Generalization
The above solution can be made more general by building a class of nested dictionary, dropping the requirements to have a fixed depth.
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
Also notice that the class approach is created so it only creates an object if the key does not exist while the setdefault approach created an empty dict on every access.
You can use the infinitely nested defaultdict trick:
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
You can use collections.defaultdict and iterate. In this case, you can define precisely a nested dictionary to reflect your data structure.
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
Result
defaultdict({'BM': defaultdict({'Holesovice': defaultdict(int, {'Butterfly': 1600})}),
'PP': defaultdict({'E-shop': defaultdict(int, {'Dresses': 1500}),
'Holesovice': defaultdict(int,
{'Ear-rings': 2000, 'Skirts': 1000})})})
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
Here post a pretty straightforward way to compose a new dictionary:
If the items in each row of list not in the corresponding depth of dictionary, just add/append the key-value pair to the dict.
code:
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)
output:
{'BM': {'Holesovice': {'Butterfly': 1600}},
'PP': {'E-shop': {'Dresses': 1500},
'Holesovice': {'Ear-rings': 2000, 'Skirts': 1000}}}
The list is defined as follows:
l = [
['PP','Ear-rings', 'Holesovice', 2000],
['PP','Skirts', 'Holesovice', 1000],
['PP','Dresses', 'E-shop', 1500],
['BM','Butterfly', 'Holesovice', 1600]
]
My aim is to have the dictionary structure as follows:
#{'PP' : {'Holesovice' : {'Ear-rings' : 2000, 'Skirts' : 1000},
# 'E-shop' : {'Dresses' : 1500}},
# 'BM' : {'Holesovice' : {'Butterfly' : 1600}}
#}
This bit of code does not return desired output:
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)
I found some posts that deal with converting lists to dictionaries here and here but I did not make it work the way I want. Is there any 'clean' way how to achieve the structure posted above?
Using dict.setdefault(key, {}) is a good way to approach the creation of nested dictionaries of fixed depth.
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
Output
{'BM': {'Holesovice': {'Butterfly': 1600}},
'PP': {'E-shop': {'Dresses': 1500},
'Holesovice': {'Ear-rings': 2000, 'Skirts': 1000}}}
Generalization
The above solution can be made more general by building a class of nested dictionary, dropping the requirements to have a fixed depth.
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
Also notice that the class approach is created so it only creates an object if the key does not exist while the setdefault approach created an empty dict on every access.
You can use the infinitely nested defaultdict trick:
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
You can use collections.defaultdict and iterate. In this case, you can define precisely a nested dictionary to reflect your data structure.
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
Result
defaultdict({'BM': defaultdict({'Holesovice': defaultdict(int, {'Butterfly': 1600})}),
'PP': defaultdict({'E-shop': defaultdict(int, {'Dresses': 1500}),
'Holesovice': defaultdict(int,
{'Ear-rings': 2000, 'Skirts': 1000})})})
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
Here post a pretty straightforward way to compose a new dictionary:
If the items in each row of list not in the corresponding depth of dictionary, just add/append the key-value pair to the dict.
code:
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)
output:
{'BM': {'Holesovice': {'Butterfly': 1600}},
'PP': {'E-shop': {'Dresses': 1500},
'Holesovice': {'Ear-rings': 2000, 'Skirts': 1000}}}
Comments
Post a Comment