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}]}
Asked By: JonnyMcFly

||

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']]
Answered By: andreihondrari

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}]}
Answered By: amanb

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}]}  
Answered By: alec_djinn

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'])
Answered By: Glen Thomas
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}]}
Answered By: DirtyBit

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"
         }
      ]
   }
}
Answered By: Cloudkollektiv

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)
Answered By: Idan Regev
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.