Home > Net >  How to update values in a nested dictionary?
How to update values in a nested dictionary?

Time:09-19

I have 2 dictionaries:

data = {
  "filter":
    {
      "and":
        [
          {
            "or":
              [
                {
                  "and":
                    [
                      {"category": "profile", "key": "languages", "operator": "IN", "value": "EN"},
                      {"category": "skill", "key": "26366", "value": 100, "operator": "EQ"},
                    ],
                },
              ],
          },
          {"or": [{"category": "skill", "key": "45165", "operator": "NE"}]},
          {"or": [{"category": "skill", "key": "48834", "value": 80, "operator": "GT"}]},
          {"or": [{"category": "profile", "key": "gender", "operator": "EQ", "value": "FEMALE"}]},
        ],
    },
}

new_val = {'26366': '11616', '45165': '11613', '48834': '11618'}

I want to update values in "data" dictionary with the values from "new_val" dictionary.

So that 26366(in "data" dict) becomes 11616(from "new_val" dict), 45165 becomes 11613, and 48834 becomes 11618. "data" dictionary nesting can be different (both up and down)

And get this result:

{
  "filter":
    {
      "and":
        [
          {
            "or":
              [
                {
                  "and":
                    [
                      {"category": "profile", "key": "languages", "operator": "IN", "value": "EN"},
                      {"category": "skill", "key": "11616", "value": 100, "operator": "EQ"},
                    ],
                },
              ],
          },
          {"or": [{"category": "skill", "key": "11613", "operator": "NE"}]},
          {"or": [{"category": "skill", "key": "11618", "value": 80, "operator": "GT"}]},
          {"or": [{"category": "profile", "key": "gender", "operator": "EQ", "value": "FEMALE"}]},
        ],
    },
}

CodePudding user response:

Use something like this:

data['filter']['and']['or']['and'][1]['key']='11616'

CodePudding user response:

To search for the keys recursively you can do:

from copy import deepcopy


def replace(d, new_vals):
    if isinstance(d, dict):
        # replace key (if there's match):
        if "key" in d:
            d["key"] = new_vals.get(d["key"], d["key"])
        for v in d.values():
            replace(v, new_vals)
    elif isinstance(d, list):
        for v in d:
            replace(v, new_vals)


new_data = deepcopy(data)
replace(new_data, new_val)
print(new_data)

Prints:

{
    "filter": {
        "and": [
            {
                "or": [
                    {
                        "and": [
                            {
                                "category": "profile",
                                "key": "languages",
                                "operator": "IN",
                                "value": "EN",
                            },
                            {
                                "category": "skill",
                                "key": "11616",
                                "value": 100,
                                "operator": "EQ",
                            },
                        ]
                    }
                ]
            },
            {"or": [{"category": "skill", "key": "11613", "operator": "NE"}]},
            {
                "or": [
                    {
                        "category": "skill",
                        "key": "11618",
                        "value": 80,
                        "operator": "GT",
                    }
                ]
            },
            {
                "or": [
                    {
                        "category": "profile",
                        "key": "gender",
                        "operator": "EQ",
                        "value": "FEMALE",
                    }
                ]
            },
        ]
    }
}

If you don't need copy of data you can omit the deepcopy:

replace(data, new_val)
print(data)

CodePudding user response:

To return an updated dict without modifying the old one:

def updated_in_depth(d, replace):
    if isinstance(d, dict):
        return {k: (replace[v] if v in replace else updated_in_depth(d, replace)) for k,v in dict.items()}
    elif isinstance(d, list):
        return [updated_in_depth(x) for x in d]
    else:
        return d

CodePudding user response:

You can build a recursive function like this

def walk_dict(d):
    if isinstance(d, list):
        for item in d:
            walk_dict(item)
    elif isinstance(d, dict):
        if 'key' in d and d['key'] in new_val:
            d['key'] = new_val[d['key']]
        for k, v in d.items():
            walk_dict(v)


walk_dict(data)
print(data)
  • Related