Convert list to a sequence of dictionary keys
Question:
I have 2 dictionaries
old_dict = {'key1': {'password1': 'password', 'sensitive_data': {'MY_PASSWORD': 'old_passwrd'}},
'key2': 'next_password', 'useless_key': 'useless_pass'}
new_dict = {'key1': {'password1': 'password', 'sensitive_data': {'MY_PASSWORD': 'default_password'}},
'key2': 'next_password'}
Next code parses the keys in the new dictionary and takes values from the old one and inserts them into the new one
def find_old(val_dict, value_list):
for i in value_list:
val_dict = val_dict[i]
return val_dict
def change_value(val_dict, value_list, value):
if len(value_list) == 1:
val_dict[value_list[0]] = value
elif len(value_list) == 2:
val_dict[value_list[0]][value_list[1]] = value
elif len(value_list) == 3:
val_dict[value_list[0]][value_list[1]][value_list[2]] = value
def parser(parse_dict, value_list=None, level=0):
if value_list is None:
value_list = []
for i in parse_dict:
value_list = value_list[:level]
value_list.append(i)
next_val = parse_dict[i]
if type(next_val) is dict:
parser(next_val, value_list, level=level + 1)
else:
old_value = (find_old(old_dict, value_list))
change_value(new_dict, value_list, old_value)
parser(parse_dict=new_dict)
print(new_dict) # {'key1': {'password1': 'password', 'sensitive_data': {'MY_PASSWORD': 'old_passwrd'}}, 'key2': 'next_password'}
the code works, but the change_value function can only work with 3 levels of dictionary keys. how to convert this function into a loop?
Answers:
There is already an operator that implements this future (Python 3.9). Its name is merge and the operator is |
, syntax: dict_1 | dict_2
(official doc).
Python will overwrite the left dictionary with the value of the keys from the right dictionary if there is an overlap, otherwise it will merge.
In your example, with these dictionaries:
old_dict = {
'key1': {
'password1': 'password',
'sensitive_data': {
'MY_PASSWORD': 'old_passwrd'
}
},
'key2': 'next_password',
'useless_key': 'useless_pass'
}
new_dict = {
'key1': {
'password1': 'password',
'sensitive_data': {
'MY_PASSWORD': 'default_password'
}
},
'key2': 'next_password'
}
The code is:
new_dict = new_dict | old_dict
If you want to remove useless_key
as well, you can use a recursion function:
def _rmv_item(obj: dict, key_to_rmv: str):
# remove useless key
if key_to_rmv in obj: obj.pop(key_to_rmv)
# search other dictionaries
for k, v in obj.items():
if isinstance(v, dict):
_rmv_item(v, key_to_rmv)
def _rmv_items(obj: dict, keys_to_rmv: list[str]):
# remove useless key
for key in keys_to_rmv:
if key in obj:
obj.pop(key)
# search other dictionaries
for k, v in obj.items():
if isinstance(v, dict):
_rmv_items(v, keys_to_rmv)
I figered out and it works
def change_value(val_dict, value_list, value):
key_seq = val_dict
for index, i in enumerate(value_list):
if index != len(value_list)-1:
key_seq = key_seq[i]
else:
key_seq[i] = value
I have 2 dictionaries
old_dict = {'key1': {'password1': 'password', 'sensitive_data': {'MY_PASSWORD': 'old_passwrd'}},
'key2': 'next_password', 'useless_key': 'useless_pass'}
new_dict = {'key1': {'password1': 'password', 'sensitive_data': {'MY_PASSWORD': 'default_password'}},
'key2': 'next_password'}
Next code parses the keys in the new dictionary and takes values from the old one and inserts them into the new one
def find_old(val_dict, value_list):
for i in value_list:
val_dict = val_dict[i]
return val_dict
def change_value(val_dict, value_list, value):
if len(value_list) == 1:
val_dict[value_list[0]] = value
elif len(value_list) == 2:
val_dict[value_list[0]][value_list[1]] = value
elif len(value_list) == 3:
val_dict[value_list[0]][value_list[1]][value_list[2]] = value
def parser(parse_dict, value_list=None, level=0):
if value_list is None:
value_list = []
for i in parse_dict:
value_list = value_list[:level]
value_list.append(i)
next_val = parse_dict[i]
if type(next_val) is dict:
parser(next_val, value_list, level=level + 1)
else:
old_value = (find_old(old_dict, value_list))
change_value(new_dict, value_list, old_value)
parser(parse_dict=new_dict)
print(new_dict) # {'key1': {'password1': 'password', 'sensitive_data': {'MY_PASSWORD': 'old_passwrd'}}, 'key2': 'next_password'}
the code works, but the change_value function can only work with 3 levels of dictionary keys. how to convert this function into a loop?
There is already an operator that implements this future (Python 3.9). Its name is merge and the operator is |
, syntax: dict_1 | dict_2
(official doc).
Python will overwrite the left dictionary with the value of the keys from the right dictionary if there is an overlap, otherwise it will merge.
In your example, with these dictionaries:
old_dict = {
'key1': {
'password1': 'password',
'sensitive_data': {
'MY_PASSWORD': 'old_passwrd'
}
},
'key2': 'next_password',
'useless_key': 'useless_pass'
}
new_dict = {
'key1': {
'password1': 'password',
'sensitive_data': {
'MY_PASSWORD': 'default_password'
}
},
'key2': 'next_password'
}
The code is:
new_dict = new_dict | old_dict
If you want to remove useless_key
as well, you can use a recursion function:
def _rmv_item(obj: dict, key_to_rmv: str):
# remove useless key
if key_to_rmv in obj: obj.pop(key_to_rmv)
# search other dictionaries
for k, v in obj.items():
if isinstance(v, dict):
_rmv_item(v, key_to_rmv)
def _rmv_items(obj: dict, keys_to_rmv: list[str]):
# remove useless key
for key in keys_to_rmv:
if key in obj:
obj.pop(key)
# search other dictionaries
for k, v in obj.items():
if isinstance(v, dict):
_rmv_items(v, keys_to_rmv)
I figered out and it works
def change_value(val_dict, value_list, value):
key_seq = val_dict
for index, i in enumerate(value_list):
if index != len(value_list)-1:
key_seq = key_seq[i]
else:
key_seq[i] = value