Home > Software engineering >  Resorting a nested json into a dictionary
Resorting a nested json into a dictionary

Time:02-15

I have a JSON string in the following format that i get from an API and need to reformat it, so that I can check the difference between two lookups (which settings are different in the different modules):

{ "modules": [
        {
            "name": "A1",
            "bar" : "AA",
            "settings" :[
                {
                    "name" : "set1",
                    "value" : "1"
                },
                {
                    "name" : "set2",
                    "value" : "2"
                }
            ]
        },
        {
            "name": "A2",
            "bar" : "DD",
            "settings" :[
                {
                    "name" : "set1",
                    "value" : "A21"
                }
            ]
        },
        {
            "name": "A1",
            "settings" :[
                {
                    "name" : "set3",
                    "value" : "1"
                }
            ]
        }
    ]
}

and need to get it into a dictionary of the format

'A1' : {
    'bar' : 'AA',
    'settings': {
        'set1' : '1',
        'set2' : '2',
        'set3' : '1'
    }....

is there any nicer, easier way to do this than, assuming I have read the string from above in a dictionary json_dict

modules_a = { module['name'] : { 'bar' : module['bar'], 'settings' : {}} for module in json_dict['modules']

for module in json_dict['modules']:
    modules_a[module['name']]['settings'].update( s['name']: s['value'] for s in module['settings'] )

CodePudding user response:

you have some errors in the input, you missed a comma after bar. Here is a more readable version:

# First, merge together the modules with the same names
concatenated_json = {'modules': []}
reference_dict = dict()

for module in json["modules"]:
    # Check whether module has a 'bar' and whether it has already been mentioned
    if module.get("bar") is not None and reference_dict.get(module["bar"]) is None:
        # Module has not been mentioned yet, add it to the fixed dict and note its reference
        concatenated_json['modules'].append(module)
        reference_dict[module["name"]] = module
    else:
        # Append to settings of a previously mentioned module
        reference_dict[module["name"]]["settings"]  = module["settings"]

json = concatenated_json

# Format dict in a required way
modules_a = {
    module["name"]:{
        "bar": module["bar"],
        "settings": {
            setting["name"]: setting["value"] for setting in module["settings"]
        }
    }
    for module in json["modules"]
}

CodePudding user response:

Here's a way to do it, although I'm not sure what you meant about "resorting".

# Preallocate result.
modules_a = {module['name']: {'settings': []} for module in json_dict['modules']}

for module in json_dict['modules']:
    obj = modules_a[module['name']]
    obj.update({k: v for k, v in module.items() if k != 'settings'})
    # Accumulate 'settings' in a list.
    obj['settings'].extend([{setting['name']: setting['value']}
                                for setting in module['settings'] ])

import json
print(json.dumps(modules_a, indent=4))

Result:

{
    "A1": {
        "settings": [
            {
                "set1": "1"
            },
            {
                "set2": "2"
            },
            {
                "set3": "1"
            }
        ],
        "bar": "AA",
        "name": "A1"
    },
    "A2": {
        "settings": [
            {
                "set1": "A21"
            }
        ],
        "bar": "DD",
        "name": "A2"
    }
}
  • Related