如何在嵌套字典中获取每个底层路径的列表(作为键列表)

How to get a list of every bottom level's path (as a list of keys) in a nested dictionary

假设我有这样的字典:

d = {'a': {'values':val}, 'b':{'fin_b': {'values':val}}, 'c':{'ca':{'fin_ca':{'values':val}}, 'cb':{'fin_cb':{'values':val}}}, 'd':{'da':{'dda':{'fin_dda':{'values':val}}}}}

我想创建一个列表,其中包含该项目所有键的每个底层项目的列表。换句话说,嵌套字典中所有项目的所有键的列表列表,而事先不知道字典中有多少层。其中一个警告是它最好忽略每个底层项目中的“值”键。换句话说,d 的正确输出是:

output = [['a'], ['b', 'fin_b'], ['c', 'ca', 'fin_ca'], ['c', 'cb', 'fin_cb'], ['d', 'da', 'dda', 'fin_dda']]

但是:

output = [['a', 'values'], ['b', 'fin_b', 'values'], ['c', 'ca', 'fin_ca', 'values'], ['c', 'cb', 'fin_cb', 'values'], ['d', 'da', 'dda', 'fin_dda', 'values']]

也可以,这是我正在努力解决的检索密钥算法。

我试过以下方法:

def get_paths(self):
  data = self.data
  groupings = []
  group = []
  def convert(d):
    nonlocal group
    for k in d.keys():
      if isinstance(d[k], dict) :
        group.append(k)
        yield from (x for x in convert(d[k]))
      else:
        group_ = group.copy()
        group = []
        yield group_

  for item in convert(data):
    groupings.append(item)
  return groupings

但我得到:

output = [['a'], ['b', 'fin_b'], ['c', 'ca', 'fin_ca'], ['cb', 'fin_cb'], ['d', 'da', 'dda', 'fin_dda']]

由于重置了最后一级的列表“组”。我也试过:

  def get_paths(self):
    data = self.data
    groupings = []
    group = []
    def convert(d):
      for k in d.keys():
        if isinstance(d[k], dict) and 'values' not in v.keys():
          yield from ([k,x] for x in convert(d[k]))
        elif 'values'  in d.keys():
          yield k

    for item in convert(data):
      groupings.append(item)
    return groupings

但问题是它 returns 一个嵌套列表,我无法绕过它:

output = ['a', ['b', 'fin_b'], ['c', ['ca', 'fin_ca']], ['c', ['cb', 'fin_cb']], ['d', ['da', ['dda', 'fin_dda']]]]

如有任何建议,我们将不胜感激。

这给出了所需的输出:

def get_paths(dictionary, current_path=None, paths_found=None):
    if current_path is None:
        current_path = []
    if paths_found is None:
        paths_found = []
    for key, value in dictionary.items():
        if isinstance(value, dict):
            get_paths(value, current_path + [key], paths_found)
        else:
            if current_path:
                paths_found.append(current_path)
    return paths_found

if __name__ == "__main__":
    d = {'a': {'values': "val"}, 'b': {'fin_b': {'values': "val"}},
         'c': {'ca': {'fin_ca': {'values': "val"}}, 'cb': {'fin_cb': {'values': "val"}}},
         'd': {'da': {'dda': {'fin_dda': {'values': "val"}}}}}
    print(get_paths(d))

您可以通过两步解决方案解决此问题:

  1. 在这种情况下,您可以检索包括叶节点在内的完整路径{"values": val}
  2. 可以过滤掉叶节点

我们可以使用迭代器:

要解决第一个问题,递归迭代器就足够了:

def iter_path(dict_in, prefix=None):
    if prefix is None:
        prefix = list()
    for key, value in dict_in.items():
        if not isinstance(value, dict):
            yield prefix + [key]
        else:
            yield from iter_path(value, prefix + [key])

对于第二点,我们可以删除生成列表的最后一个条目:

def iter_path_not_last(dict_in):
    for path in iter_path(dict_in, prefix=None):
        yield p[:-1]

终于

paths = [p for p in iter_path_not_last(d)]