我有一个嵌套的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密钥,如果值为'e838'
,则获取该特定字典中其他密钥的值。因此,从上面的例子中我可能需要xyz
键的值。
为此,我创建了一个递归循环函数,如下所示,它正在工作。不过我的问题是,是否有更好/更简单的方法来做到这一点。如果我需要使用密钥mnx获取所有值,那么在同一代码中可以做什么。谢谢。
注意:我在jxmlease lib的帮助下将XML转换为dict。
def iterate_dict(dict1,key1,val1):
for key, value in dict1.items():
if key == key1 and value == val1:
return dict1
if isinstance(value,list):
for item1 in value:
if isinstance(item1,dict):
for k,v in item1.items():
if k == key1 and v == val1:
return item1
if isinstance(value,dict):
for key,var in value.items():
if key == key1 and var == val1:
return value
else:
return iterate_dict(value,key1,val1)
答案 0 :(得分:1)
您可以排序将该词典“压扁”成一个词典列表,然后根据需要进行查询:
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']
答案 1 :(得分:0)
m['abc']['bcd'] + m['abc']['ghi']['mnc']
出:
[{'cde': '100', 'def': '200', 'efg': '300'},
{'cde': '3000', 'def': '500', 'efg': '4000'},
{'mnx': 'e838', 'wyew': '2232', 'xyz': '8827382'}]
你应该建立一个dict列表来迭代,而不是使用原始数据。
答案 2 :(得分:0)
此代码使用递归生成器进行搜索,因此它会在找到它们时生成所有解决方案。
当iterate_dict
找到带有所需(键,值)对的dict时,它会调用filter_dict
,这会创建一个包含输出的新dict。这个新的dict包含传递给filter_dict
的dict的项目,除了它过滤掉所需的(键,值)对,它还过滤掉了dict可能包含的任何列表或词典。但是,iterate_dict
将递归处理那些寻找进一步匹配的列表或词。如果您不希望iterate_dict
查找更多匹配项,则可以轻松修改代码,以便它不会执行此操作;请看下面。
如果要搜索包含所需键的dicts并且不关心与该键关联的值,可以将None
作为val
参数传递,或者只省略该arg。
我已经稍微修改了你的数据,所以我们可以测试递归搜索包含匹配的字典中的进一步匹配。
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)
<强>输出强>
{'yew': '55', 'xyzz': '44'}
{'xyz': '8827382', 'wyew': '2232'}
这是一个搜索,查找包含'mnx'
键的所有词组:
for d in iterate_dict(data, 'mnx'):
print(d)
<强>输出强>
{'ijk': '3', 'abc': '1'}
{'xyzz': '44', 'yew': '55'}
{'wyew': '2232', 'xyz': '8827382'}
如果您不希望在找到匹配项后递归搜索每个字典以进一步匹配,只需将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)