Reputation: 43
I want to translate a list of dictionaries into a nested JSON. I want to dynamically populate fields.I want to group all the signals for a specific category. I have tried different ways, but can't able generate the exact format required. Need some help for logic to generate the JSON
My Input
signal_list = [
{'sig_id': 667, 'sig_name': 'RotorSpeed', 'Category': 'Gbox'},
{'sig_id': 672, 'sig_name': 'GeneratorSpeed', 'Category': 'Genarator'},
{'sig_id': 673, 'sig_name': 'NacelleSpeed', 'Category': 'Nacelle'},
{'sig_id': 668, 'sig_name': 'RotorDirection', 'Category': 'Gbox'}
]
Code I have tried:
d = defaultdict(list)
for t in signals:
field_list = d[t['Category']]
new_d = {'sig_name': t['sig_name'], 'sig_id': t['sig_id'], 'Category': t['Category']}
field_list.append(defaultdict(list, new_d))
Current output
[
{
"Gbox":[
{
"sig_name":"RotorSpeed",
"sig_id":667
},
{
"sig_name":"RotorDirection",
"sig_id":668
}
]
},
{
"Genarator":[
{
"sig_name":"GeneratorSpeed",
"sig_id":672
}
]
},
{
"Signals":[
{
"sig_name":"NacelleSpeed",
"SignalID":673
}
]
}
]
(Required)My output should look as below
[
{
"Category":"Gbox",
"Signals":[
{
"sig_name":"RotorSpeed",
"sig_id":667
},
{
"sig_name":"RotorDirection",
"sig_id":668
}
]
},
{
"Category":"Genarator",
"Signals":[
{
"sig_name":"GeneratorSpeed",
"sig_id":672
}
]
},
{
"Category":"Nacelle",
"Signals":[
{
"sig_name":"NacelleSpeed",
"SignalID":673
}
]
}
]
Upvotes: 1
Views: 389
Reputation: 851
Please refer to the itertools
documentation and specifically the groupby
function.
import json
import itertools
dta = signal_list = [
{'sig_id': 667, 'sig_name': 'RotorSpeed', 'Category': 'Gbox'},
{'sig_id': 672, 'sig_name': 'GeneratorSpeed', 'Category': 'Genarator'},
{'sig_id': 673, 'sig_name': 'NacelleSpeed', 'Category': 'Nacelle'},
{'sig_id': 668, 'sig_name': 'RotorDirection', 'Category': 'Gbox'}
]
# this key is simply to be used on each dictionary to get the 'Category'
key = lambda dct: dct.get('Category')
# group works best with a sorted iterable. So let's sort by "Category' since that's
# your grouping key.
a = itertools.groupby(sorted(dta, key=key), key)
# groupby returns a generator like object that has tuples of (key, value)
# the value is also a generator like object that just has each item from the iterable
# that matches your grouping key. To get all the items we just turn them into a list
b = [{"Category": k, "Signals": list(v)} for k,v in a]
# using json to print it out in a nice format
print(json.dumps(b, indent=1))
Output:
[
{
"Category": "Gbox",
"Signals": [
{
"sig_id": 667,
"sig_name": "RotorSpeed",
"Category": "Gbox"
},
{
"sig_id": 668,
"sig_name": "RotorDirection",
"Category": "Gbox"
}
]
},
{
"Category": "Genarator",
"Signals": [
{
"sig_id": 672,
"sig_name": "GeneratorSpeed",
"Category": "Genarator"
}
]
},
{
"Category": "Nacelle",
"Signals": [
{
"sig_id": 673,
"sig_name": "NacelleSpeed",
"Category": "Nacelle"
}
]
}
]
If I understand correctly, you want to remove the Category key from each dictionary in your lists. You could do this. If you wanted to remove multiple keys, just edit that function and do some sort of loop inside :)
def remove_key(dct:dict, key):
"""
Simply takes a dictionary, copies it and remove the key of interest
from the copy and returns the copy.
"""
# This function will be used in a list comprehension so it has to
# return the dictionary and not just pop the key
dct_ = dct.copy()
_ = dct_.pop(key)
return dct_
b = [{"Category": k, "Signals": [remove_key(dct, 'Category') for dct in v]} for k,v in a]
print(json.dumps(b, indent=1))
Output
[
{
"Category": "Gbox",
"Signals": [
{
"sig_id": 667,
"sig_name": "RotorSpeed"
},
{
"sig_id": 668,
"sig_name": "RotorDirection"
}
]
},
{
"Category": "Genarator",
"Signals": [
{
"sig_id": 672,
"sig_name": "GeneratorSpeed"
}
]
},
{
"Category": "Nacelle",
"Signals": [
{
"sig_id": 673,
"sig_name": "NacelleSpeed"
}
]
}
]
Upvotes: 1