Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set "nth" element of a nested python dict with given list location?

If I have a dict for example

d = { 'a': {
            "x": [],
            "y": {
                "z": {
                    "1": 'loser'
                        }
                 }
            }
    }

print(d['a']['y']['z']['1']) #=> loser

However, I don't know how many nested items are in this dict. Instead I have a list of keys like:

['a', 'y', 'z', '1']

What is an elegant way to set d['a']['y']['z']['1'] = 'winner'?

Here's what I've tried:

l = ['a', 'y', 'z', '1']

def change_the_value(d, l, value):
    if len(l) == 1:
        d[l[0]] = value
    if len(l) == 2:
        d[l[0]][l[1]] = value
    if len(l) == 3:
        d[l[0]][l[1]][l[2]] = value
    if len(l) == 4:
        d[l[0]][l[1]][l[2]][l[3]] = value
    # ... ad infinitum
    return d

change_the_value(d, l, 'winner')
print(d) # => {'a': {'x': [], 'y': {'z': {'1': 'winner'}}}}
like image 689
Conner Avatar asked Dec 15 '18 21:12

Conner


2 Answers

You can use a simple for loop:

_path = ['a', 'y', 'z', '1']
d = {'a': {'x': [], 'y': {'z': {'1': 'loser'}}}}
_start = d
for i in _path[:-1]:
   _start = _start[i]

_start[_path[-1]] = 'winner'
print(d)

Output:

{'a': {'x': [], 'y': {'z': {'1': 'winner'}}}}

You can also use recursion (if you do not mind creating a new structure for d):

def update(_d, _path):
  return {a:'winner' if a == _path[-1] and len(_path) == 1 else 
    update(b, _path[1:]) if a == _path[0] else b for a, b in _d.items()}

print(update(d, ['a', 'y', 'z', '1']))

Output:

{'a': {'x': [], 'y': {'z': {'1': 'winner'}}}}
like image 156
Ajax1234 Avatar answered Oct 02 '22 23:10

Ajax1234


If you can be sure that the list of keys is valid, you can use functools.reduce.

>>> from functools import reduce 
>>>
>>> keys = ['a', 'y', 'z', '1']                                                                                     
>>> d = { 'a': { 
...:             "x": [], 
...:             "y": { 
...:                 "z": { 
...:                     "1": 'loser' 
...:                         } 
...:                  } 
...:             } 
...:     }                                                                                                             
>>>                                                                                                                    
>>> the_dict = reduce(dict.get, keys[:-1], d)                                                                          
>>> the_dict[keys[-1]] = 'winner'                                                                                      
>>> d                                                                                                                  
{'a': {'x': [], 'y': {'z': {'1': 'winner'}}}}
like image 42
timgeb Avatar answered Oct 02 '22 21:10

timgeb