如何在嵌套字典中查找所有出现的键,同时跟踪外部字典键值?

Posted

技术标签:

【中文标题】如何在嵌套字典中查找所有出现的键,同时跟踪外部字典键值?【英文标题】:How to find all occurrence of a key in nested dict, but also keep track of the outer dict key value? 【发布时间】:2018-07-19 03:43:22 【问题描述】:

我在 *** 上进行了搜索,发现以下代码允许我递归地搜索嵌套 dict 中的键值。但是,我还想跟踪外部字典的键值。我该怎么做?

从下面链接中 Alfe 的回答中,我可以使用下面的代码获取嵌套字典中键的所有值。 Find all occurrences of a key in nested python dictionaries and lists

data = 'item1': 
  'name': 'dummy',
  'type': 'dummy1',

'item2': 
  'name': 'dummy',
  'type': 'dummy1',
  'label':'label2'
,

'item3': 
  'name': 'dummy',
  'type': 'dummy1',
  'label':'label3',

'item4': 
  'name': 'dummy',
  'type': 'dummy1'


 def find(key, dictionary):
    for k, v in dictionary.items():
        if k == key:
            yield v
        elif isinstance(v, dict):
            for result in find(key, v):
                yield result
        elif isinstance(v, list):
            for d in v:
                for result in find(key, d):
                    yield result


In[1]:list(find('label', data))
Out[1]: 
['label2', 'label3']

但是,我还需要记录外部 dict 键,如下所示。我该怎么做?此外,我的数据可能有不止一层。

'item2':'label2',
'item3':'label3'

我还发现此链接中的 recursive_lookup 写得非常整齐。但是,当我尝试运行它时,它会返回 None

Find keys in nested dictionary

def recursive_lookup(k, d):
    if k in d:
        return d[k]
    for v in d.values():
        if isinstance(v, dict):
            return recursive_lookup(k, v)
    return None

当我调用 recursive_lookup('label', data) 时,它正在返回 None

如果有人可以为我指出为什么上面的代码不起作用,那也太好了!

【问题讨论】:

【参考方案1】:

无论您的嵌套有多深,这都应该可以工作(至少达到堆栈限制)。跟踪字典键的请求有点尴尬——我用一个元组来返回这对。请注意,如果找到的值在最外层的字典中,则不会是元组格式。

def recursive_lookup(key, d):
    if key in d:
        return d[key]

    for k, v in d.items():
        if isinstance(v, dict):
            result = recursive_lookup(key, v)

            if result:
                return k, result


print(recursive_lookup('label', data))

输出:

('item2', 'label2')

这是一个有点混乱的版本(我并不喜欢内部函数,但至少累加器列表不是参数,也不是全局的),但会返回所有找到的嵌套项的列表堆栈限制,除了最外层的键:

def recursive_lookup(key, d):
    def _lookup(key, d):
        if key in d:
            return d[key]

        for k, v in d.items():
            if isinstance(v, dict):
                result = _lookup(key, v)

                if result:
                    accumulator.append((k, result))

    accumulator = []
    _lookup(key, d)
    return accumulator

输出:

[('item3', 'label3'), ('item2', 'label2')]

如果你想输出一个字典,这可以很容易地修改——用accumulator = accumulator.append((k, result))accumulator[k] = result替换accumulator = [],但这可能很难用,而且你不能存储重复关键条目。

至于你的最后一个问题,你得到None 的原因是因为内部循环returns 在检查第一项后是否找到了某些东西。由于label 位于items() 数组的第二个位置,因此它永远不会被查看。

【讨论】:

感谢@ggorlen。看起来它只返回键的第一个实例,而不是完整列表。只是想知道如何让它找到所有出现的键? 我补充说 - 根据您的问题,不确定您想要哪一个。【参考方案2】:

functions 以元组列表的形式返回路径和值。

def dict_key_lookup(_dict, key, path=[]):
    results = []
    if isinstance(_dict, dict):
        if key in _dict:
            results.append((path+[key], _dict[key]))
        else:
            for k, v in _dict.items():
                results.extend(dict_key_lookup(v, key, path= path+[k]))
    elif isinstance(_dict, list):
        for index, item in enumerate(_dict):
            results.extend(dict_key_lookup(item, key, path= path+[index]))
    return results

希望这会有所帮助。

【讨论】:

【参考方案3】:

首先创建一个类似的列表

outerKeyList = []

然后,只要您想存储密钥,例如在返回要搜索的项目之前,只需运行

outerKeyList.append(key). 

这将为您提供递归函数之外的所有键的方便列表。

【讨论】:

【参考方案4】:

如果您的dict 中只有一个嵌套的dict,那么您可以使用dict 理解:

In [9]: def find(label, data):
   ...:     return outer_key: inner_val for outer_key, outer_val in data.items() for inner_key, inner_val in outer_val.items() if inner_key == label
   ...:

In [10]: find('label', data)
Out[10]: 'item2': 'label2', 'item3': 'label3'

【讨论】:

感谢@aydow。我确实有一个可能有不止一层的字典。但这很高兴知道!【参考方案5】:

您可以使用NestedDict

from ndicts.ndicts import NestedDict

data = 'item1': 'name': 'dummy', 'type': 'dummy1',
        'item2': 'label': 'label2', 'name': 'dummy', 'type': 'dummy1',
        'item3': 'label': 'label3', 'name': 'dummy', 'type': 'dummy1',
        'item4': 'name': 'dummy', 'type': 'dummy1'
nd = NestedDict(data)

nd_filtered= NestedDict()
for key, value in nd.items():
    if "label" in key:
        new_key = tuple(level for level in key if level != "label")
        nd_filtered[new_key] = value
>>> nd_filtered
NestedDict('item2': 'label2', 'item3': 'label3')
>>> nd_filtered.to_dict()
'item2': 'label2', 'item3': 'label3'

您也可以考虑.extract,尽管它不会为您提供您所要求的确切输出

>>> nd.extract["", "label"]
NestedDict('item2': 'label': 'label2', 'item3': 'label': 'label3')

安装ndictspip install ndicts

【讨论】:

以上是关于如何在嵌套字典中查找所有出现的键,同时跟踪外部字典键值?的主要内容,如果未能解决你的问题,请参考以下文章

在python的嵌套json字典中查找一个值

如何重命名字典列表中深度嵌套的键(Python 3)?

如何在 Python 中的 Queue 对象中查找不同字典中的键?

使用列表中的项目更改嵌套字典的字典中的值?

具有相同键的(嵌套)字典的 Pythonic 替代方案?

查找列表中有多少嵌套字典键