如何找到嵌套字典中所有出现的键,又如何跟踪外部字典键值?

时间:2018-07-19 03:43:22

标签: python dictionary nested

我在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

当我打电话给None时,它将返回recursive_lookup('label', data)

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

4 个答案:

答案 0 :(得分:1)

无论嵌套的深度有多深(无论如何都达到堆栈限制),此方法都应该起作用。跟踪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')]

如果要输出字典,可以很容易地对其进行修改-将accumulator = []替换为accumulator = {},而将accumulator.append((k, result))替换为accumulator[k] = result,但这可能很难处理,并且您不能存储重复的键条目。

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

答案 1 :(得分:1)

函数返回路径和值以及元组列表。

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

希望这会有所帮助。

答案 2 :(得分:0)

首先创建一个列表,例如

outerKeyList = []

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

outerKeyList.append(key). 

这将为您提供递归功能之外所有键的便捷列表。

答案 3 :(得分:0)

如果您的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'}