Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: Apply function to values in nested dictionary

I have an arbitrarily deep set of nested dictionary:

x = {'a': 1, 'b': {'c': 6, 'd': 7, 'g': {'h': 3, 'i': 9}}, 'e': {'f': 3}}

and I'd like to basically apply a function to all the integers in the dictionaries, so like map, I guess, but for nested dictionaries.

So: map_nested_dicts(x, lambda v: v + 7) would be the sort of goal.

I'm stuck as to the best way to perhaps store the layers of keys to then put the modified value back into its correct position.

What would the best way/approach to do this be?

like image 788
Jean-Luc Avatar asked Oct 04 '15 15:10

Jean-Luc


People also ask

How do you apply a function to each value in a dictionary?

Use a dictionary comprehension to map a function over all values in a dictionary. Use the syntax {key: f(value) for key, value in dict. items()} to apply the function f to each value in the dictionary dict .

How do you assign a value to a nested dictionary?

Adding elements to a Nested Dictionary One way to add a dictionary in the Nested dictionary is to add values one be one, Nested_dict[dict][key] = 'value'.

How do you get a value from a nested dictionary Python?

Access Values using get() Another way to access value(s) in a nested dictionary ( employees ) is to use the dict. get() method. This method returns the value for a specified key. If the specified key does not exist, the get() method returns None (preventing a KeyError ).

Can you put a function inside a dictionary Python?

The technique is when you have a python dictionary and a function that you intend to use on it. You insert an extra element into the dict, whose value is the name of the function. When you're ready to call the function you issue the call indirectly by referring to the dict element, not the function by name.


2 Answers

Visit all nested values recursively:

import collections

def map_nested_dicts(ob, func):
    if isinstance(ob, collections.Mapping):
        return {k: map_nested_dicts(v, func) for k, v in ob.iteritems()}
    else:
        return func(ob)

map_nested_dicts(x, lambda v: v + 7)
# Creates a new dict object:
#    {'a': 8, 'b': {'c': 13, 'g': {'h': 10, 'i': 16}, 'd': 14}, 'e': {'f': 10}}

In some cases it's desired to modify the original dict object (to avoid re-creating it):

import collections

def map_nested_dicts_modify(ob, func):
    for k, v in ob.iteritems():
        if isinstance(v, collections.Mapping):
            map_nested_dicts_modify(v, func)
        else:
            ob[k] = func(v)

map_nested_dicts_modify(x, lambda v: v + 7)
# x is now
#    {'a': 8, 'b': {'c': 13, 'g': {'h': 10, 'i': 16}, 'd': 14}, 'e': {'f': 10}}

If you're using Python 3:

  • replace dict.iteritems with dict.items

  • replace import collections with import collections.abc

  • replace collections.Mapping with collections.abc.Mapping

like image 156
vaultah Avatar answered Sep 21 '22 18:09

vaultah


If you need it to work for both lists and dicts in arbitrary nesting:

def apply_recursive(func, obj):
    if isinstance(obj, dict):  # if dict, apply to each key
        return {k: apply_recursive(func, v) for k, v in obj.items()}
    elif isinstance(obj, list):  # if list, apply to each element
        return [apply_recursive(func, elem) for elem in obj]
    else:
        return func(obj)
like image 40
elgehelge Avatar answered Sep 18 '22 18:09

elgehelge