Home > Back-end >  Python loop over nested dict inside nested list with same key names
Python loop over nested dict inside nested list with same key names

Time:04-11

I have a json file like this:

{
    "results": [        
        {
            "rule": {
                "description": "a",
                "engine": "b",
                "id": 0,
                "name": "name",
                "test_requires": "all",
            }
        }
        {
            "rule": {
                "description": "a",
                "engine": "b",
                "id": 1,
                "name": "name",
                "test_requires": "one",
            }
        }
        {
            "rule": {
                "description": "a",
                "engine": "b",
                "id": 2,
                "name": "main",
                "test_requires": "one",
            }
        }
    ]
    }

So i want to iterate through this file and get several key values from every nested dict which are also nested to a list

something like :

result = []
reuslt2 = []
templates = json.load(jsonfile)
for item in templates[results][0]:
    result.append(templates[results][0][id]
    result2.append(templates[results[0][name]

Obviously this doesn't work cause it only loops from the first nested dict with id:0

How can i make a successful loop into this nested dict - list going all the way through to work in python ?

Thank you.

CodePudding user response:

i think what you meant (correctly formatted of json file)-

{
"results": [        
    {
        "rule": {
            "description": "a",
            "engine": "b",
            "id": 0,
            "name": "name",
            "test_requires": "all"
        }
    },
    {
        "rule": {
            "description": "a",
            "engine": "b",
            "id": 1,
            "name": "name",
            "test_requires": "one"
        }
    },
    {
        "rule": {
            "description": "a",
            "engine": "b",
            "id": 2,
            "name": "main",
            "test_requires": "one"
        }
    }
]
}

as your json file

and this is what you want-

import json

result = []
result2 = []

with open('./records.json') as f:
    templates = json.load(f)
    for item in templates["results"]:
        result.append(item["rule"]["id"])
        result2.append(item["rule"]["name"])
print(result)
print(result2)

CodePudding user response:

If you don't know beforehand on what level id and name might be, you'll have to use a recursion:

templates = {
    "results": [        
        {
            "rule": {
                "description": "a",
                "engine": "b",
                "id": 0,
                "name": "name",
                "test_requires": "all",
            }
        },
        {
            "rule": {
                "description": "a",
                "engine": "b",
                "id": 1,
                "name": "name",
                "test_requires": "one",
            }
        },
        {
            "rule": {
                "description": "a",
                "engine": "b",
                "id": 2,
                "name": "main",
                "test_requires": "one",
            }
        }
    ]
    }

ids = []
names = []

def get_ids_and_names(templ):
    if isinstance(templ, dict):
        if 'id' in templ:
            ids.append(templ['id'])
        if 'name' in templ:
            names.append(templ['name'])
        for val in templ.values():
            get_ids_and_names(val)
    elif isinstance(templ, list):
        for elt in templ:
            get_ids_and_names(elt)

get_ids_and_names(templates)

print(ids)
print(names)

Output:

[0, 1, 2]
['name', 'name', 'main']

CodePudding user response:

You could pack the id and name values from each record in templates["results"] into tuples, zip them, and then unpack it into the results:

result, result2 = zip(*((rec["rule"]["id"], rec["rule"]["name"]) for rec in templates["results"]))

Result:

(0, 1, 2), ('name', 'name', 'main')

If you want lists instead:

result, result2 = map(
    list,
    zip(*((rec["rule"]["id"], rec["rule"]["name"]) for rec in templates["results"]))
)

Result:

[0, 1, 2], ['name', 'name', 'main']
  • Related