I would like to understand how I can rename keys in a list of dicts recursively without mutation of method parameters.
I have the following list of dicts:
filters = [
{
'or': [
{
'and': [
{
"column": {
"type": "string",
"name": "field_name"
},
"operator": "==",
"value": "field_value"
},
{
"column": {
"type": "string",
"name": "field_2_name"
},
"operator": "!=",
"value": "field_2_value"
}
]
},
{
'not': [
{
"column": {
"type": "number",
"name": "field_3_name"
},
"operator": "==",
"value": "field_3_value"
}
]
}
]
}]
This is what I expect to achieve:
filters = [
{
'or': [
{
'and': [
{'field': 'field_name', 'op': '==', 'value': 'field_value'},
{'field': 'field_2_name', 'op': '!=', 'value': 'field_2_value'},
]
},
{
'not': [
{'field': 'field_3_name', 'op': '==', 'value': 'field_3_value'}
]
},
],
}
]
Any way I can get around with this?
Thanks!
CodePudding user response:
A recursive function should work, changing the sub-dicts if they contain column
and otherwise recursing deeper for other operations.
def change(collection):
if isinstance(collection, list):
return [change(d) for d in collection]
if isinstance(collection, dict):
if "column" in collection:
return {
"field": collection["column"]["name"],
"value": collection["value"],
"op": collection["operator"]
}
else:
return {op: change(val) for op, val in collection.items()}
res = change(filters)
Result:
[{'or': [{'and': [{'field': 'field_name', 'op': '==', 'value': 'field_value'},
{'field': 'field_2_name', 'op': '!=', 'value': 'field_2_value'}]},
{'not': [{'field': 'field_3_name', 'op': '==', 'value': 'field_3_value'}]}]}]
CodePudding user response:
Simple, you write a recursive function that fixes up your data structure. I assume that you don't want to change the original.
def fixup(d):
if isinstance(d,list):
return [fixup(x) for x in d]
elif not isinstance(d,dict):
return d
elif needs_mangling(d):
return mangler(d)
else:
return {k:fixup(v) for k,v in d.items()}
Add mangling functions as required.
CodePudding user response:
Does this satisfy your scenario?
def change(obj):
# if recusive parameter is a list
if isinstance(obj, list):
# run next recursive iteration for each item in list
for i in range(len(obj)):
obj[i] = change(obj[i])
return obj
# if parameter is a dict
if isinstance(obj, dict):
# 1st case is to convert the object
if "operator" in obj:
return {"field": obj["column"]["name"], "op": obj["operator"], "value": obj["value"]}
# 2nd case is to go deeper into recursion with object values
else:
for key in obj:
obj[key] = change(obj[key])
return obj
print(change(filters))