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