如何展平嵌套字典并在冲突时使用内部值



问题

对于以下字典:

{'id': 1, 'label': 'hello', 'remove_me': {'world': {'keep_me': 52}}}

我想创建一个没有remove_meworld键的新字典。

编辑更新:

总而言之,我想做以下几点:

如果项的值是嵌套字典。使用内部结果更新新字典,同时从主字典中删除当前键值。

如果项的值不是嵌套字典,请使用键 value 更新新字典。

公认的答案涵盖了这一点。

我试过什么?

{k:v for (k,v) in d.items() if not k == 'remove_me'}

收益 率:

{'id': 1, 'label': 'hello'}

不完全是我需要的,因为我正在删除嵌套的字典。

期望输出:

{'id': 1, 'label': 'hello','keep_me': 52}
dico = {'id': 1, 'label': 'hello', 'remove_me': {'world': {'keep_me': 52}}}
# Just what you have done
new_dico = {k:v for (k,v) in dico.items() if not k == 'remove_me'}
# Plus this line
new_dico.update(dico['remove_me']['world'])
print(new_dico)
# {'id': 1, 'label': 'hello', 'keep_me': 52}

受我在这里读到的启发,主词典的扁平化函数,无论您的关键词典有多深:

dico = {'id': 1, 'label': 'hello', 'remove_me': {'world': {'keep_me': 52}}}
def dFlatten(dico, d = {}):
for k, v in dico.items():
if isinstance(v, dict):
dFlatten(v)
else:
d[k] = v
return d
dico = dFlatten(dico)
print(dico)
# {'id': 1, 'label': 'hello', 'keep_me': 52}

例如,使用更深的二分法:

dico2 = {'id': 1, 'label': 'hello', 'stuff1': {'stuff2': {'remove_me': {'world': {'keep_me': 52}}}}}
dico2 = dFlatten(dico2)
print(dico2)         
# {'id': 1, 'label': 'hello', 'keep_me': 52}

具有相同 dFlatten 功能的多个深度键

dico3 = {'id': 1, 'label': 'hello', 'deep': {'L1': {'L2': 52}}, 'remove_me': {'world': {'keep_me': 52}}}
dico3 = dFlatten(dico3)
print(dico3)         
# {'id': 1, 'label': 'hello', 'keep_me': 52, 'L2': 52}

你可以试试

d = {'id': 1, 'label': 'hello', 'remove_me': {'world': {'keep_me': 52}}}
for k, v in list(d.items()):
if isinstance(v, dict):
for i in v:
if isinstance(v[i], dict):
d.update(v[i])
else:
d.update(v)
del d[k]
print(d)

输出

{'id': 1, 'label': 'hello', 'keep_me': 52}

此代码将检查每个项的值是否是字典,如果是,它将使用内部结果更新字典并从主字典中删除当前键值。 这样,最后,d dict 将只保留一个键和一个字符串值,而没有嵌套字典。

您可能需要更具体地了解字典的结构以及如何处理多个键。无论如何,这里有一个递归方法,它符合你的描述,并尝试保留尽可能多的密钥。

def clean_kvp(k, v, invalid_keys=["remove_me", "world"]):
if k not in invalid_keys:
return [(k, v)]
if not isinstance(v, dict):
return []
return [
(kkk, vvv)
for kk, vv in v.items()
for kkk, vvv in clean_kvp(kk, vv)
]
def clean_dict(d):
return {
kk: vv
for k, v in d.items()
for kk, vv in clean_kvp(k, v)
}

几个测试:

>>> d = {'id': 1, 'label': 'hello', 'remove_me': {'world': {'keep_me': 52}}}
>>> clean_dict(d)
{'id': 1, 'label': 'hello', 'keep_me': 52}
>>> d = {
...     'id': 1,
...     'label': 'hello',
...     'remove_me': {'world': {'keep_me': 52, 'test': 2}}
... }
>>> clean_dict(d)
{'id': 1, 'label': 'hello', 'keep_me': 52, 'test': 2}
>>> d = {'id': 1, 'label': {'test': 'hello'}}
>>> clean_dict(d)
{'id': 1, 'label': {'test': 'hello'}}

扁平化字典本身就是一件大事。这能实现你的目标吗?(未经测试,我正在手机上打字(:

def flattenDict(myDict, blacklist):
returnDict = {}
for key, val in myDict:
If isinstance(val, "dict"):
myDict.update(flattenDict(val))
elif key in blacklist:
continue 
elif val in blacklist:
continue
returnDict[key] = val
return returnDict 
cleanDict = flattenDict(myDict, ["remove_me", "world"])

我认为这可以在一般情况下使用单个递归函数来完成,如下所示:

def remove_keys(d, keys):
if not isinstance(d, dict):
return d 
ret = {}
for k, v in d.items():
clean = remove_keys(v, keys)
if k not in bad_keys:
ret[k] = clean
else:
if isinstance(clean, dict):
ret.update(clean)
return ret
bad_keys = ['remove_me', 'world']
d = {'id': 1, 'label': 'hello', 'remove_me': {'world': {'keep_me': 52}}}
remove_keys(d, bad_keys)
# {'id': 1, 'label': 'hello', 'keep_me': 52}
d = {'id': 1, 'label': 'hello', 'remove_me': 52}
remove_keys(d, bad_keys)
# {'id': 1, 'label': 'hello'}
d = {'id': 1, 'label': 'hello', 'dont_remove_me': {'world': {'keep_me': 52}}}
remove_keys(d, bad_keys)
# {'id': 1, 'label': 'hello', 'dont_remove_me': {'keep_me': 52}}

最新更新