如何展平嵌套字典并在碰撞时使用内部值
How to flatten a nested dict and use inner values on collision
问题
对于以下词典:
{'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}
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}
您可能需要更具体地了解字典的结构,以及如何处理多个键。无论如何,这是一种符合您的描述并尝试保留尽可能多的密钥的递归方法。
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'}}
你可以试试
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 字典将只保留一个键和一个字符串值,而没有嵌套字典。
扁平化字典本身就是一件完整的事情。这是否实现了您的目标? (未经测试,我正在输入 phone a.t.m。):
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}}
问题
对于以下词典:
{'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}
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}
您可能需要更具体地了解字典的结构,以及如何处理多个键。无论如何,这是一种符合您的描述并尝试保留尽可能多的密钥的递归方法。
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'}}
你可以试试
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 字典将只保留一个键和一个字符串值,而没有嵌套字典。
扁平化字典本身就是一件完整的事情。这是否实现了您的目标? (未经测试,我正在输入 phone a.t.m。):
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}}