如何展平嵌套的字典并在碰撞时使用内部值
Posted
技术标签:
【中文标题】如何展平嵌套的字典并在碰撞时使用内部值【英文标题】:How to flatten a nested dict and use inner values on collision 【发布时间】:2020-09-18 04:09:48 【问题描述】:问题
对于以下字典:
'id': 1, 'label': 'hello', 'remove_me': 'world': 'keep_me': 52
我想创建一个没有 remove_me
或 world
键的新字典。
编辑更新:
总而言之,我想做以下事情:
如果一个项目的值是一个嵌套字典。使用内部结果更新新字典,同时从主字典中删除当前键值。
如果项目的值不是嵌套字典,则使用键值更新新字典。
接受的答案涵盖了这一点。
我尝试了什么?
k:v for (k,v) in d.items() if not k == 'remove_me'
产量:
'id': 1, 'label': 'hello'
不完全是我需要的,因为我正在删除嵌套的字典。
期望的输出:
'id': 1, 'label': 'hello','keep_me': 52
【问题讨论】:
还有其他类似的键可以应用吗?如果它只是有问题的特定键,那么手动分配该键值对似乎会更容易 如果“remove_me”有多个键,或者有一个不是“世界”的键,你想做什么? 【参考方案1】: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
受我在此处阅读的内容的启发,主 dict 的扁平化函数,无论您的 key-dict 是什么深度:
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
例如更深的 dico:
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
【讨论】:
【参考方案2】:你可以试试
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
此代码将检查每个项目的值是否为 dict,如果是,它将使用内部结果更新 dict 并从主 dict 中删除当前键值。 这样,最后,d dict 将只保留一个键和一个字符串值,而没有嵌套的 dicts。
【讨论】:
这只是删除嵌套的字典不是特定的键。这会因d = 'id': 1, 'label': 'hello', 'remove_me': 'world': 'keep_me': 52, 'test':2
之类的字典而失败它还会错误地删除带有d = 'id': 1, 'label': 'test':'hello'
之类的字典的好键
是的@MateenUlhaq,您只需将remove_me
更改为dont_remove_me
即可让灾难发生。
旁注,我不得不将for k, v in d.items():
更改为for k, v in list(d.items()):
以避免RuntimeError: dictionary keys changed during iteration
@awarrier99 感谢您根据您的说明更改了代码
@LeoArad 它仍然会删除好的键。例如:d = 'id': 1, 'label': 'hello', 'dont_remove_me': 'world': 'keep_me': 52
返回'id': 1, 'label': 'hello', 'keep_me': 52
dont_remove_me
发生了什么?【参考方案3】:
您可能需要更具体地了解字典的结构,以及如何处理多个键。无论如何,这是一种符合您的描述并尝试保留尽可能多的键的递归方法。
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'
【讨论】:
【参考方案4】:我认为这可以在一般情况下使用单个递归函数来完成,例如:
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
【讨论】:
【参考方案5】:扁平化字典本身就是一回事。这是否实现了您的目标? (未经测试,我上午在手机上打字):
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"])
【讨论】:
以上是关于如何展平嵌套的字典并在碰撞时使用内部值的主要内容,如果未能解决你的问题,请参考以下文章