Home > Software design >  Remove a list of string-dotted named keys from a Python dictionary
Remove a list of string-dotted named keys from a Python dictionary

Time:09-17

That's now been some days I'm looking for a solution to my problem. I won't cover all the things I tried so far and will just explain my problem.

Here are my two inputs:

unused_field_list = ['a.b', 'b.d.y', 'c.g', 'z']

my_dictionnary =
{
  "a": {
    "b": {
      "key": "value"
    },
    "c": {
      "f": {
        "key": "value"
      }
    }
  },
  "b": {
    "d": {
      "y": {
        "key": "value"
      }
    },
    "g": {
      "key": "value"
    }
  },
  "c": {
    "g" : {
      "key": "value"
    }
  },
  "z": {
    "key": "value"
  }
} 

Here is the output I would like:

{
  "a": {
    "c": {
      "f": {
        "key": "value"
      }
    }
  },
  "b": {
    "g": {
      "key": "value"
    }
  }
}

So what I try to achieve is removing the "keys" I do have in my unused_field_list from my dictionary. It's not mandatory but another good thing would be to also totally remove a key if it does not contain lower level keys (like it is the case for b.d and c keys in my example. Depth of the dict is not known in advance and varies.

I think this is not doable with a straightforward approach but I really hope there is a way of doing it quite simply.

CodePudding user response:

You can use recursion:

paths = ['a.b', 'b.d.y', 'c.g', 'z']
d = {'a': {'b': {'key': None}, 'c': {'f': {'key': None}}}, 'b': {'d': {'y': {'key': 'value'}}, 'g': {'key': 'value'}}, 'c': {'g': {'key': 'value'}}, 'z': {'key': 'value'}}
def rm_d(d, p = []):
   if not isinstance(d, dict):
      return d
   r = {a:rm_d(b, p [a]) for a, b in d.items() if '.'.join(p [a]) not in paths}
   return {a:b for a, b in r.items() if not isinstance(b, dict) or b}

print(rm_d(d))

Output:

{'a': {'c': {'f': {'key': None}}}, 'b': {'g': {'key': 'value'}}}

CodePudding user response:

unused_field_list = ['a.b', 'b.d.y', 'c.g', 'z']

my_dictionnary = {
  "a": {
    "b": {
      "key": "value"
    },
    "c": {
      "f": {
        "key": "value"
      }
    }
  },
  "b": {
    "d": {
      "y": {
        "key": "value"
      }
    },
    "g": {
      "key": "value"
    }
  },
  "c": {
    "g" : {
      "key": "value"
    }
  },
  "z": {
    "key": "value"
  }
}

def filter_dict(node, filter=None, path=None):
    
    if type(node) != dict:
        return node
    
    res = {}
    
    if filter is None:
        filter = []
    
    if path is None:
        path = ""
    
    for k, v in node.items():
        subpath = f"{path}.{k}" if path != "" else k
        if subpath not in filter:
            subnode = filter_dict(v, filter, subpath)
            if subnode != {}:
                res [k] = subnode
    
    return res

res = filter_dict(my_dictionnary, unused_field_list)

print(res)
  • Related