【问题标题】: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
【问题描述】:

我在 stackoverflow 上进行了搜索,发现以下代码允许我递归地搜索嵌套 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

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

【问题讨论】:

    标签: python dictionary nested


    【解决方案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

        【讨论】:

          猜你喜欢
          • 2017-12-05
          • 2012-04-06
          • 2012-05-21
          • 2018-09-02
          • 1970-01-01
          • 2020-02-16
          • 1970-01-01
          • 2018-08-17
          相关资源
          最近更新 更多