Convert list of key/value pairs to nested dictionary
Question:
Input data:
data = [
['QR', ''],
['Cust', ''],
['fea', 'restroom'],
['chain', 'pa'],
['store', 'cd'],
['App', ''],
['End', 'EndnR'],
['Request', '0'],
['Sound', '15'],
['Target', '60'],
['Is', 'TRUE']
]
I want to turn this into a dictionary, and each blank value indicates the start of a new, nested sub-dictionary.
Desired output:
{
'QR': {
'Cust': {
'fea': 'restroom ',
'chain': 'pa',
'store': 'cd'
},
'App': {
'End': 'EndnR',
'Request': '0',
'Sound': '15',
'Target': '60',
'Is': 'true'
},
}
}
Here is my code so far:
from collections import defaultdict
res = defaultdict(dict)
for i in data:
res[i[0]] = i[1]
print(res)
But it only creates a flat dictionary with some blank values, not a nested dictionary.
Answers:
try this:
result = {}
nbr_keys = 0
keys = [ item[0] for item in data if item[1] == "" ]
for index, item in enumerate(data):
if index == 0:
if item[1] == "":
key = item[0]
di[item[0]] = {}
else:
if item[1] == "":
di[key].update({item[0]: {}})
nbr_keys +=1
else:
di[key][keys[nbr_keys]].update({item[0]: item[1]})
which outputs this:
{'QR': {'Cust': {'fea': 'restroom', 'chain': 'pa', 'store': 'cd'},
'App': {'End': 'EndnR',
'Request': '0',
'Sound': '15',
'Target': '60',
'Is': 'TRUE'}}}
Consider the following approach using itertools.groupby
function:
from itertools import groupby
data=[['QR', ''], ['Cust', ''], ['fea', 'restroom'], ['chain', 'pa'], ['store', 'cd'], ['App', ''], ['End', 'EndnR'],
['Request', '0'], ['Sound', '15'], ['Target', '60'], ['Is', 'TRUE']]
def l_to_dict(data):
store = []
for new_d, gr in groupby(data, lambda x: x[1] == ''):
if not store:
store.append({})
if new_d: # having new nested dict case
for k, v in gr:
store[-1][k] = {}
store.append(store[-1][k]) # append last empty dict to the back
else:
curr = store[-1] if len(store) == 1 else store.pop()
for k, v in gr:
curr[k] = v
return store[0]
pprint(l_to_dict(data), width=10, sort_dicts=False)
{'QR': {'Cust': {'fea': 'restroom',
'chain': 'pa',
'store': 'cd'},
'App': {'End': 'EndnR',
'Request': '0',
'Sound': '15',
'Target': '60',
'Is': 'TRUE'}}}
Input data:
data = [
['QR', ''],
['Cust', ''],
['fea', 'restroom'],
['chain', 'pa'],
['store', 'cd'],
['App', ''],
['End', 'EndnR'],
['Request', '0'],
['Sound', '15'],
['Target', '60'],
['Is', 'TRUE']
]
I want to turn this into a dictionary, and each blank value indicates the start of a new, nested sub-dictionary.
Desired output:
{
'QR': {
'Cust': {
'fea': 'restroom ',
'chain': 'pa',
'store': 'cd'
},
'App': {
'End': 'EndnR',
'Request': '0',
'Sound': '15',
'Target': '60',
'Is': 'true'
},
}
}
Here is my code so far:
from collections import defaultdict
res = defaultdict(dict)
for i in data:
res[i[0]] = i[1]
print(res)
But it only creates a flat dictionary with some blank values, not a nested dictionary.
try this:
result = {}
nbr_keys = 0
keys = [ item[0] for item in data if item[1] == "" ]
for index, item in enumerate(data):
if index == 0:
if item[1] == "":
key = item[0]
di[item[0]] = {}
else:
if item[1] == "":
di[key].update({item[0]: {}})
nbr_keys +=1
else:
di[key][keys[nbr_keys]].update({item[0]: item[1]})
which outputs this:
{'QR': {'Cust': {'fea': 'restroom', 'chain': 'pa', 'store': 'cd'},
'App': {'End': 'EndnR',
'Request': '0',
'Sound': '15',
'Target': '60',
'Is': 'TRUE'}}}
Consider the following approach using itertools.groupby
function:
from itertools import groupby
data=[['QR', ''], ['Cust', ''], ['fea', 'restroom'], ['chain', 'pa'], ['store', 'cd'], ['App', ''], ['End', 'EndnR'],
['Request', '0'], ['Sound', '15'], ['Target', '60'], ['Is', 'TRUE']]
def l_to_dict(data):
store = []
for new_d, gr in groupby(data, lambda x: x[1] == ''):
if not store:
store.append({})
if new_d: # having new nested dict case
for k, v in gr:
store[-1][k] = {}
store.append(store[-1][k]) # append last empty dict to the back
else:
curr = store[-1] if len(store) == 1 else store.pop()
for k, v in gr:
curr[k] = v
return store[0]
pprint(l_to_dict(data), width=10, sort_dicts=False)
{'QR': {'Cust': {'fea': 'restroom',
'chain': 'pa',
'store': 'cd'},
'App': {'End': 'EndnR',
'Request': '0',
'Sound': '15',
'Target': '60',
'Is': 'TRUE'}}}