python 如何找到嵌套dict中所有出现的键,同时跟踪外部dict的键值?

46qrfjad  于 2023-01-04  发布在  Python
关注(0)|答案(5)|浏览(147)

我搜索了stackoverflow,发现下面的代码允许我递归地搜索嵌套dict中的键值。但是,我还想跟踪外部dict的键值。我该怎么做呢?
从下面链接中Alfe的回答,我可以使用下面的代码获取嵌套dict.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
如果有人能为我指出为什么上面的代码不工作,这将是伟大的太!

u5rb5r59

u5rb5r591#

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

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

希望这个有用。

2guxujil

2guxujil2#

不管嵌套有多深(至少达到堆栈限制),这都应该可以工作。跟踪dict的键的请求有点笨拙--我使用了一个元组来返回对。注意,如果找到的值在最外层字典中,它就不会是元组格式。

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

如果您想输出一个dict,可以很容易地修改它--将accumulator = []替换为accumulator = {},将accumulator.append((k, result))替换为accumulator[k] = result,但是这样做可能不方便,并且您不能存储重复的键条目。
至于你的最后一个问题,你得到None的原因是因为内部循环returns在检查第一项是否找到了什么之后,因为labelitems()数组的第二个位置,它从来没有被检查过。

jxct1oxe

jxct1oxe3#

首先创建如下列表

outerKeyList = []

然后,每当您想要存储一个键时,比如在返回要搜索的项之前,只需运行

outerKeyList.append(key).

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

2ic8powd

2ic8powd4#

如果在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'}
vnzz0bqm

vnzz0bqm5#

您可以使用NestedDict

from 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

相关问题