使用python3以特定的顺序遍历嵌套dict

2024-06-16 11:40:49 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个嵌套的dict,它有列表和dict,如下所示。在

m = {'abc': 
      {'bcd': [
               {'cde':'100','def':'200','efg':'300'},
               {'cde':'3000','def':'500','efg':'4000'}
              ], 
       'ghi': 
         {'mnc': [
                  {'xyz':'8827382','mnx':'e838','wyew':'2232'}
                 ]
         }
       }
     }

我的要求是匹配mnx key,如果值是'e838',那么就获得该特定dict中其他键的值。因此,从上面的示例中,我可能需要xyzkey的值。在

为此,我创建了一个递归循环函数,如下所示。然而,我的问题是,是否有更好/更简单的方法来做这件事。如果我需要用mnx键获取所有值,那么在同一代码中可以做什么呢。谢谢。在

注意:我在jxmleeslib的帮助下将XML转换成dict。在

^{pr2}$

Tags: key示例列表defdictabcxyzghi
3条回答

这段代码使用递归生成器进行搜索,因此它将在找到它们时生成所有的解决方案。在

iterate_dict找到具有所需(键、值)对的dict时,它调用filter_dict,这将创建一个新dict来包含输出。这个新dict包含传递给filter_dict的dict项,除了过滤掉所需的(键、值)对之外,它还过滤掉该dict可能包含的任何列表或dict。但是,iterate_dict将递归地处理这些列表或dict,以寻找进一步的匹配项。如果您不希望iterate_dict查找进一步的匹配项,那么可以很容易地修改代码,这样就不会这样做;请参见下面的内容。在

如果要搜索包含所需键的dict,而不关心与该键相关联的值,可以将None作为val参数传递,或者忽略该参数。在

我稍微修改了您的数据,这样我们就可以在包含匹配项的dict中测试递归搜索进一步的匹配项。在

def filter_dict(d, key):
    return {k: v for k, v in d.items() 
        if k != key and not isinstance(v, (dict, list))}

def iterate_dict(d, key, val=None):
    if key in d and (val is None or d[key] == val):
        yield filter_dict(d, key)
    yield from iterate_list(d.values(), key, val)

def iterate_list(seq, key, val):
    for v in seq:
        if isinstance(v, list):
            yield from iterate_list(v, key, val)
        elif isinstance(v, dict):
            yield from iterate_dict(v, key, val)

# test

data = {
    'abc': {
        'bcd': [
            {'cde':'100', 'def':'200', 'efg':'300'},
            {'cde':'3000', 'def':'500', 'efg':'4000'},
            {'abc': '1', 'mnx': '2', 'ijk': '3', 
                'zzz': {'xyzz':'44', 'mnx':'e838', 'yew':'55'}
            },
        ], 
        'ghi': {
            'mnc': [
                {'xyz':'8827382', 'mnx':'e838', 'wyew':'2232'}
            ]
        }
    }
}

for d in iterate_dict(data, 'mnx', 'e838'):
    print(d)

输出

^{pr2}$

以下是搜索包含'mnx'键的所有dict:

for d in iterate_dict(data, 'mnx'):
    print(d)

输出

{'ijk': '3', 'abc': '1'}
{'xyzz': '44', 'yew': '55'}
{'wyew': '2232', 'xyz': '8827382'}

如果您不希望在每个dict中找到匹配项后递归地搜索进一步的匹配项,只需将iterate_dict更改为:

def iterate_dict(d, key, val=None):
    if key in d and (val is None or d[key] == val):
        yield filter_dict(d, key)
    else:
        yield from iterate_list(d.values(), key, val)

您可以将dict“展平”成dict列表,然后根据需要进行查询:

def flatten_dict(d):
    flattened = []
    current = {}
    for k, v in d.items():
        if isinstance(v, dict):
            flattened.extend(flatten_dict(v))
        elif isinstance(v, list):
            flattened.extend(sum((flatten_dict(v_d) for v_d in v), []))
        else:
            current[k] = v
    if len(current) > 0:
        flattened = [current] + flattened
    return flattened

def values_in_flattened(flattened, key):
    return list(filter(None, (d.get(key, None) for d in flattened))) or None

m = {'abc': {'bcd':[{'cde':'100','def':'200','efg':'300'},{'cde':'3000','def':'500','efg':'4000'}], 'ghi':{'mnc':[{'xyz':'8827382','mnx':'e838','wyew':'2232'}]}}}
mf = flatten_dict(m)
efg_vals = values_in_flattened(mf, 'efg')
print(mf)
print(efg_vals)

>>>
[{'xyz': '8827382', 'mnx': 'e838', 'wyew': '2232'}, {'def': '200', 'efg': '300', 'cde': '100'}, {'def': '500', 'efg': '4000', 'cde': '3000'}]
['300', '4000']
m['abc']['bcd'] + m['abc']['ghi']['mnc']

输出:

^{pr2}$

您应该构建一个dict列表来迭代,而不是使用原始数据。在

相关问题 更多 >