【问题标题】:Python--Finding Parent Keys for a specific value in a nested dictionaryPython - 在嵌套字典中查找特定值的父键
【发布时间】:2013-09-20 01:54:53
【问题描述】:

当值可能在嵌套字典中多次存在时,我正在努力处理嵌套字典,并为特定值返回嵌套的父键。 例如:

example_dict = { 'key1' : 'value1',
                 'key2' : 'value2',
                 'key3' : { 'key3a': 'value3a' },
                 'key4' : { 'key4a': { 'key4aa': 'value4aa',
                                       'key4ab': 'value4ab',
                                       'key4ac': 'value1'},
                            'key4b': 'value4b'}
                }

您会注意到 'value1' 在上面的字典中出现了两次,我想创建一个函数来返回单个列表或一系列列表,以标识不同的父键,在这种情况下将是 'key1' 和 ('key4', 'key4a', key4ac)。

此类问题已在本网站的其他地方处理过,当时正在寻找的值仅出现一次,并且可以通过以下递归函数轻松处理:

def find_key(d,key):
    for k,v in d.items():
        if isinstance(v,dict):
            p = find_key(v,key)
            if p:
                return [k] + p
        elif v == key:
            return [k]

print find_key(example_dict,'value4ac').

如果你在字典上运行上面的代码,我只能得到一个父键的答案。 任何帮助将非常感激, 谢谢!

【问题讨论】:

  • 您是反复进行此类搜索,还是只进行一次?如果你做的不止一个,你几乎肯定会想要创建一个反向映射字典,然后访问它,而不是每次都蛮力搜索整个字典。

标签: python dictionary nested key dictionary-comprehension


【解决方案1】:

这是一种解决方案:

from copy import copy

example_dict = { 'key1' : 'value1',
                 'key2' : 'value2',
                 'key3' : { 'key3a': 'value3a' },
                 'key4' : { 'key4a': { 'key4aa': 'value4aa',
                                       'key4ab': 'value4ab',
                                       'key4ac': 'value1'},
                            'key4b': 'value4b'}
                }


result = []
path = []

def get_keys(d, target):
    for k, v in d.iteritems():
        path.append(k)
        if isinstance(v, dict):
            get_keys(v, target)
        if v == target:
            result.append(copy(path))
        path.pop()

结果:

>>> get_keys(example_dict, 'value1')
>>> result
[['key1'], ['key4', 'key4a', 'key4ac']]

【讨论】:

    【解决方案2】:

    除非您只进行一次搜索(或者您在内存上受到极大限制但有 CPU 时间来消耗......),否则您将需要构建一个反向查找字典,然后您就可以使用它。


    为了使这更容易,我将分两步完成。首先,将嵌套字典转换为键路径字典:

    def keypaths(nested):
        for key, value in nested.iteritems():
            if isinstance(value, collections.Mapping):
                for subkey, subvalue in keypaths(value):
                    yield [key] + subkey, subvalue
            else:
                yield [key], value
    

    如果它的作用不明显,请打印出list(keypaths(example_dict))


    现在,如何创建反向词典?对于一对一的映射,您可以这样做:

    reverse_dict = {value: keypath for keypath, value in keypaths(example_dict)}
    

    但是对于像你这样的多对一映射,反向是一对多,所以我们需要将每个值映射到一个键列表。所以:

    reverse_dict = {}
    for keypath, value in keypaths(example_dict):
        reverse_dict.setdefault(value, []).append(keypath)
    

    现在你不需要任何花哨的东西了;只需在reverse_dict 上进行正常的字典查找:

    >>> reverse_dict['value2']
    [('key2',)]
    >>> reverse_dict['value1']
    [('key1',), ('key4', 'key4a', 'key4ac')]
    >>> reverse_dict['value3']
    KeyError: 'value3'
    

    如果您希望最后一个返回[] 而不是引发KeyError,则可以使用defaultdict(list) 而不是普通的dict,然后就不需要setdefault


    无论如何,构建这种反向映射所用的时间只比通过蛮力进行一次搜索所用的时间长一点,所以如果你进行 100 次搜索,它会快近 100 倍方式,也更简单。

    【讨论】:

    • 这很棒。感谢您花时间解释并将其放在一起。反向映射是有意义的。我提出问题的动机是处理可能在字典样式返回的响应中多次出现状态:'error' 的 json 数据,然后使用 'error' 键路径来识别错误的数据馈送组件,以及错误(即“错误消息”)。我想知道 json 数据是否通常以标准化格式出现,例如有标准的序列化程序,或者在这种情况下是否必须基于正在处理的 json 格式进行编码?--Cheers
    • 简单易懂。谢谢@abarnet
    • import collections
    猜你喜欢
    • 2020-02-16
    • 1970-01-01
    • 2022-07-05
    • 2016-11-14
    • 1970-01-01
    • 2015-07-18
    • 1970-01-01
    • 1970-01-01
    • 2022-01-06
    相关资源
    最近更新 更多