Удалите список именованных ключей со строковыми точками из словаря Python

#python #dictionary #recursion #key

Вопрос:

Вот уже несколько дней я ищу решение своей проблемы. Я не буду описывать все то, что я пробовал до сих пор, и просто объясню свою проблему.

Вот мои два входа:

 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"
  }
} 
 

Вот результат, который я хотел бы получить:

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

Поэтому я пытаюсь добиться того, чтобы удалить «ключи», которые у меня есть в моем unused_field_list словаре, из моего словаря. Это не обязательно, но еще одной хорошей вещью было бы также полностью удалить ключ, если он не содержит ключей более низкого уровня (как в случае b.d с c ключами и в моем примере. Глубина диктанта заранее не известна и варьируется.

Я думаю, что это невозможно сделать с помощью простого подхода, но я действительно надеюсь, что есть способ сделать это довольно просто.

Ответ №1:

Вы можете использовать рекурсию:

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

Выход:

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

Ответ №2:

 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)