Home > Net >  Rename dict keys in a list of dicts recursively
Rename dict keys in a list of dicts recursively

Time:12-15

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))
  • Related