Home > Back-end >  Iterate a nested dictionary and filter specific fields
Iterate a nested dictionary and filter specific fields

Time:11-05

I have an example object which is mixed of lists and dicts:

{
    "field_1" : "aaa",
    "field_2": [
        {
        "name" : "bbb",
          .....
        "field_4" : "ccc",
        "field_need_to_filter" : False,
        },

        {
        "name" : "ddd",
          .....
        "details": [
            {
            "name" : "eee",
            ....
            "details" : [
                {
                "name": "fff",
                .....
                "field_10": {
                    "field_11": "rrr",
                    ...
                    "details": [
                        {
                        "name": "xxx",
                        ...
                        "field_need_to_filter": True,
                        },
                        {
                        "name": "yyy",
                        ...
                        "field_need_to_filter": True,
                        },
                        {
                        "field_13": "zzz",
                        ...
                        "field_need_to_filter": False,
                        }
                                ]
                                }
                },


        ]}]}

       ]
}

I'd like to iterate this dictionary and add all the corresponding fields for name where field_need_to_filter is True, so for this example, expected output would be: ["ddd.eee.fff.xxx", "ddd.eee.fff.yyy"]. I've been looking at this for too long and my brain stops working now, any help would be appreciated. Thanks.

I understand that I can use recursive function, this is what i have so far, can someone tell me what I'm missing because it seems not iterate and stopped in the first level of fields:

def iterate_func(data_details: list, parent_field_name: str) -> str:
    
    out = []
    
    for field in data_details:
        field_name = (construct from the xxx.xxx pattern)
        
        if field["name"] == "ddd":
            iterate_func(field['details'], field_name)
            
            if "field_need_to_filter" in field and field["field_need_to_filter"] == True:
                value = field["field_need_to_filter"]
            
                out.append(field_name)
                return out
        
        elif ???
            
        else:
            return []
            
    return out

CodePudding user response:

Ok, it took me some time to think about the different cases and fix bugs, but this works (at least on your example of dict); note that it assumes that dicts containing "field_need_to_filter": True are end-points (the function doesn't delve deeper into those)). I'll be glad to add explanations to the code if you want some.

mydict = {
    "field_1" : "aaa",
    "field_2": [
        {
        "name" : "bbb",

        "field_4" : "ccc",
        "field_need_to_filter" : False,
        },

        {
        "name" : "ddd",

        "details": [
            {
            "name" : "eee",

            "details" : [
                {
                "name": "fff",

                "field_10": {
                    "field_11": "rrr",

                    "details": [
                        {
                        "name": "xxx",

                        "field_need_to_filter": True,
                        },
                        {
                        "name": "yyy",

                        "field_need_to_filter": True,
                        },
                        {
                        "field_13": "zzz",

                        "field_need_to_filter": False,
                        }
                                ]
                                }
                },


        ]}]}

       ]
}

def filter_paths(thing, path=''):
    if type(thing) == dict:
        # if this dict has a name, log it
        if thing.get("name"):
            path  = '.'   thing["name"]
        # if this dict has "...filter": True, we've reached an end point, and return the path
        if thing.get("field_need_to_filter") and thing["field_need_to_filter"]:
            return [path]
        # else we delve deeper
        result = []
        for key in thing:
            result  = [deep_path for deep_path in filter_paths(thing[key], path)]
        return result
    
    # if the current object is a list, we simply delve deeper
    elif type(thing) == list:
        result = []
        for element in thing:
            result  = [deep_path for deep_path in filter_paths(element, path)]
        return result

    # We've reached a dead-end, so we return an empty list
    else:
        return []
        
filter_paths(mydict)
# Out[204]: ['.ddd.eee.fff.xxx', '.ddd.eee.fff.yyy']

CodePudding user response:

If that is your correct code, the you call iterate_fun instead of iterate_func after the check for field name of ddd

  • Related