Python: Replace values in nested dictionary
Question:
I want to replace the values (formated as strings) with the same values as integers, whenever the key is ‘current_values‘.
d = {'id': '10', 'datastreams': [{'current_value': '5'}, {'current_value': '4'}]}
Desired Output:
d = {'id': '10', 'datastreams': [{'current_value': 5}, {'current_value': 4}]}
Answers:
Can be done with list comprehension:
d['datastreams'] = [{'current_value': int(ds['current_value'])} if ('current_value' in ds) else ds for ds in d['datastreams']]
You can use ast.literal_eval to evaluate the underlying value for items
with current_value
key in the d[‘datastreams’] list. Then check whether the type is an int
using isinstance
for such values. Finally, type cast such values to int
.
import ast
d = {'id': '10', 'datastreams': [{'current_value': '5'}, {'current_value': '4'}]}
for i in d['datastreams']:
for k,v in i.items():
if 'current_value' in k and isinstance(ast.literal_eval(v),int):
i[k] = int(v)
#Output:
print(d)
{'id': '10', 'datastreams': [{'current_value': 5}, {'current_value': 4}]}
A general approach (assuming you don’t know in advance which key of the dict is pointing to a list) would be to iterate over the dict and check the type of its values and then iterate again into each value if needed.
In your case, your dictionary may contain a list of dictionaries as values, so it is enough to check if a value is of type list, if so, iterate over the list and change the dicts you need.
It can be done recursively with a function like the following:
def f(d):
for k,v in d.items():
if k == 'current_value':
d[k] = int(v)
elif type(v) is list:
for item in v:
if type(item) is dict:
f(item)
>>> d = {'id': '10', 'datastreams': [{'current_value': '5'}, {'current_value': '4'}]}
>>> f(d)
>>> d
{'id': '10', 'datastreams': [{'current_value': 5}, {'current_value': 4}]}
You could use this method
which would loop through checks for current_value in list and change it to integer by passing the value through int() function:
for value in d.values():
for element in value:
if 'current_value' in element:
element['current_value'] = int(element['current_value'])
d = {'id': '10', 'datastreams': [{'current_value': '5'}, {'current_value': '4'}]}
for elem in d['datastreams']: # for each elem in the list datastreams
for k,v in elem.items(): # for key,val in the elem of the list
if 'current_value' in k: # if current_value is in the key
elem[k] = int(v) # Cast it to int
print(d)
OUTPUT:
{'id': '10', 'datastreams': [{'current_value': 5}, {'current_value': 4}]}
The following piece of code replaces (substrings of) values in a dictionary. It works for nested json structures and copes with json, list and string types. You can easily add other types if needed.
def dict_replace_value(d: dict, old: str, new: str) -> dict:
x = {}
for k, v in d.items():
if isinstance(v, dict):
v = dict_replace_value(v, old, new)
elif isinstance(v, list):
v = list_replace_value(v, old, new)
elif isinstance(v, str):
v = v.replace(old, new)
x[k] = v
return x
def list_replace_value(l: list, old: str, new: str) -> list:
x = []
for e in l:
if isinstance(e, list):
e = list_replace_value(e, old, new)
elif isinstance(e, dict):
e = dict_replace_value(e, old, new)
elif isinstance(e, str):
e = e.replace(old, new)
x.append(e)
return x
# See input and output below
output = dict_replace_value(input, 'string', 'something')
Input:
input = {
'key1': 'a string',
'key2': 'another string',
'key3': [
'a string',
'another string',
[1, 2, 3],
{
'key1': 'a string',
'key2': 'another string'
}
],
'key4': {
'key1': 'a string',
'key2': 'another string',
'key3': [
'a string',
'another string',
500,
1000
]
},
'key5': {
'key1': [
{
'key1': 'a string'
}
]
}
}
Output:
print(output)
{
"key1":"a something",
"key2":"another something",
"key3":[
"a something",
"another something",
[
1,
2,
3
],
{
"key1":"a something",
"key2":"another something"
}
],
"key4":{
"key1":"a something",
"key2":"another something",
"key3":[
"a something",
"another something",
500,
1000
]
},
"key5":{
"key1":[
{
"key1":"a something"
}
]
}
}
Taking alec_djinn’s solution little farther to handle also nested dicts:
def f(d):
for k,v in d.items():
if k == 'current_value':
d[k] = int(v)
elif type(v) is list:
for item in v:
if type(item) is dict:
f(item)
if type(v) is dict:
f(v)
I want to replace the values (formated as strings) with the same values as integers, whenever the key is ‘current_values‘.
d = {'id': '10', 'datastreams': [{'current_value': '5'}, {'current_value': '4'}]}
Desired Output:
d = {'id': '10', 'datastreams': [{'current_value': 5}, {'current_value': 4}]}
Can be done with list comprehension:
d['datastreams'] = [{'current_value': int(ds['current_value'])} if ('current_value' in ds) else ds for ds in d['datastreams']]
You can use ast.literal_eval to evaluate the underlying value for items
with current_value
key in the d[‘datastreams’] list. Then check whether the type is an int
using isinstance
for such values. Finally, type cast such values to int
.
import ast
d = {'id': '10', 'datastreams': [{'current_value': '5'}, {'current_value': '4'}]}
for i in d['datastreams']:
for k,v in i.items():
if 'current_value' in k and isinstance(ast.literal_eval(v),int):
i[k] = int(v)
#Output:
print(d)
{'id': '10', 'datastreams': [{'current_value': 5}, {'current_value': 4}]}
A general approach (assuming you don’t know in advance which key of the dict is pointing to a list) would be to iterate over the dict and check the type of its values and then iterate again into each value if needed.
In your case, your dictionary may contain a list of dictionaries as values, so it is enough to check if a value is of type list, if so, iterate over the list and change the dicts you need.
It can be done recursively with a function like the following:
def f(d):
for k,v in d.items():
if k == 'current_value':
d[k] = int(v)
elif type(v) is list:
for item in v:
if type(item) is dict:
f(item)
>>> d = {'id': '10', 'datastreams': [{'current_value': '5'}, {'current_value': '4'}]}
>>> f(d)
>>> d
{'id': '10', 'datastreams': [{'current_value': 5}, {'current_value': 4}]}
You could use this method
which would loop through checks for current_value in list and change it to integer by passing the value through int() function:
for value in d.values():
for element in value:
if 'current_value' in element:
element['current_value'] = int(element['current_value'])
d = {'id': '10', 'datastreams': [{'current_value': '5'}, {'current_value': '4'}]}
for elem in d['datastreams']: # for each elem in the list datastreams
for k,v in elem.items(): # for key,val in the elem of the list
if 'current_value' in k: # if current_value is in the key
elem[k] = int(v) # Cast it to int
print(d)
OUTPUT:
{'id': '10', 'datastreams': [{'current_value': 5}, {'current_value': 4}]}
The following piece of code replaces (substrings of) values in a dictionary. It works for nested json structures and copes with json, list and string types. You can easily add other types if needed.
def dict_replace_value(d: dict, old: str, new: str) -> dict:
x = {}
for k, v in d.items():
if isinstance(v, dict):
v = dict_replace_value(v, old, new)
elif isinstance(v, list):
v = list_replace_value(v, old, new)
elif isinstance(v, str):
v = v.replace(old, new)
x[k] = v
return x
def list_replace_value(l: list, old: str, new: str) -> list:
x = []
for e in l:
if isinstance(e, list):
e = list_replace_value(e, old, new)
elif isinstance(e, dict):
e = dict_replace_value(e, old, new)
elif isinstance(e, str):
e = e.replace(old, new)
x.append(e)
return x
# See input and output below
output = dict_replace_value(input, 'string', 'something')
Input:
input = {
'key1': 'a string',
'key2': 'another string',
'key3': [
'a string',
'another string',
[1, 2, 3],
{
'key1': 'a string',
'key2': 'another string'
}
],
'key4': {
'key1': 'a string',
'key2': 'another string',
'key3': [
'a string',
'another string',
500,
1000
]
},
'key5': {
'key1': [
{
'key1': 'a string'
}
]
}
}
Output:
print(output)
{
"key1":"a something",
"key2":"another something",
"key3":[
"a something",
"another something",
[
1,
2,
3
],
{
"key1":"a something",
"key2":"another something"
}
],
"key4":{
"key1":"a something",
"key2":"another something",
"key3":[
"a something",
"another something",
500,
1000
]
},
"key5":{
"key1":[
{
"key1":"a something"
}
]
}
}
Taking alec_djinn’s solution little farther to handle also nested dicts:
def f(d):
for k,v in d.items():
if k == 'current_value':
d[k] = int(v)
elif type(v) is list:
for item in v:
if type(item) is dict:
f(item)
if type(v) is dict:
f(v)