- Python Nested Dictionary
- Create a Nested Dictionary
- The dict() Constructor
- Access Nested Dictionary Items
- Change Nested Dictionary Items
- Add or Update Nested Dictionary Items
- Merge Two Nested Dictionaries
- Remove Nested Dictionary Items
- Remove an Item by Key
- Remove Last Inserted Item
- Iterate Through a Nested Dictionary
- Getting a key’s value in a nested dictionary
- 4 Answers 4
- Get value from dictionary given a list of nested keys
- 5 Answers 5
Python Nested Dictionary
A dictionary can contain another dictionary, which in turn can contain dictionaries themselves, and so on to arbitrary depth. This is known as nested dictionary.
Nested dictionaries are one of many ways to represent structured information (similar to ‘records’ or ‘structs’ in other languages).
Create a Nested Dictionary
A nested dictionary is created the same way a normal dictionary is created. The only difference is that each value is another dictionary.
Let’s build a dictionary that stores employee record.
D = 'emp1': 'name': 'Bob', 'job': 'Mgr'>, 'emp2': 'name': 'Kim', 'job': 'Dev'>, 'emp3': 'name': 'Sam', 'job': 'Dev'>>
The dict() Constructor
There are several ways to create a nested dictionary using a type constructor called dict().
To create a nested dictionary, simply pass dictionary key:value pair as keyword arguments to dict() Constructor.
D = dict(emp1 = 'name': 'Bob', 'job': 'Mgr'>, emp2 = 'name': 'Kim', 'job': 'Dev'>, emp3 = 'name': 'Sam', 'job': 'Dev'>) print(D) # Prints , # 'emp2': , # 'emp3': >
You can use dict() function along with the zip() function, to combine separate lists of keys and values obtained dynamically at runtime.
IDs = ['emp1','emp2','emp3'] EmpInfo = ['name': 'Bob', 'job': 'Mgr'>, 'name': 'Kim', 'job': 'Dev'>, 'name': 'Sam', 'job': 'Dev'>] D = dict(zip(IDs, EmpInfo)) print(D) # Prints , # 'emp2': , # 'emp3': >
You’ll often want to create a dictionary with default values for each key. The fromkeys() method offers a way to do this.
IDs = ['emp1','emp2','emp3'] Defaults = 'name': '', 'job': ''> D = dict.fromkeys(IDs, Defaults) print(D) # Prints , # 'emp2': , # 'emp3': >
Access Nested Dictionary Items
You can access individual items in a nested dictionary by specifying key in multiple square brackets.
D = 'emp1': 'name': 'Bob', 'job': 'Mgr'>, 'emp2': 'name': 'Kim', 'job': 'Dev'>, 'emp3': 'name': 'Sam', 'job': 'Dev'>> print(D['emp1']['name']) # Prints Bob print(D['emp2']['job']) # Prints Dev
If you refer to a key that is not in the nested dictionary, an exception is raised.
print(D['emp1']['salary']) # Triggers KeyError: 'salary'
To avoid such exception, you can use the special dictionary get() method. This method returns the value for key if key is in the dictionary, else None , so that this method never raises a KeyError .
# key present print(D['emp1'].get('name')) # Prints Bob # key absent print(D['emp1'].get('salary')) # PrintsNone
Change Nested Dictionary Items
To change the value of a specific item in a nested dictionary, refer to its key.
D = 'emp1': 'name': 'Bob', 'job': 'Mgr'>, 'emp2': 'name': 'Kim', 'job': 'Dev'>, 'emp3': 'name': 'Sam', 'job': 'Dev'>> D['emp3']['name'] = 'Max' D['emp3']['job'] = 'Janitor' print(D['emp3']) # Prints
Add or Update Nested Dictionary Items
Adding or updating nested dictionary items is easy. Just refer to the item by its key and assign a value. If the key is already present in the dictionary, its value is replaced by the new one.
D = 'emp1': 'name': 'Bob', 'job': 'Mgr'>, 'emp2': 'name': 'Kim', 'job': 'Dev'>, 'emp3': 'name': 'Sam', 'job': 'Dev'>> D['emp3'] = 'name': 'Max', 'job': 'Janitor'> print(D) # Prints , # 'emp2': , # 'emp3': >
If the key is new, it is added to the dictionary with its value.
D = 'emp1': 'name': 'Bob', 'job': 'Mgr'>, 'emp2': 'name': 'Kim', 'job': 'Dev'>, 'emp3': 'name': 'Sam', 'job': 'Dev'>> D['emp4'] = 'name': 'Max', 'job': 'Janitor'> print(D) # Prints , # 'emp2': , # 'emp3': , # 'emp4': >
Merge Two Nested Dictionaries
Use the built-in update() method to merge the keys and values of one nested dictionary into another. Note that this method blindly overwrites values of the same key if there’s a clash.
D1 = 'emp1': 'name': 'Bob', 'job': 'Mgr'>, 'emp2': 'name': 'Kim', 'job': 'Dev'>> D2 = 'emp2': 'name': 'Sam', 'job': 'Dev'>, 'emp3': 'name': 'Max', 'job': 'Janitor'>> D1.update(D2) print(D1) # Prints , # 'emp2': , # 'emp3': >
Here the ’emp2′ record is updated while ’emp3′ is added to the dictionary.
Remove Nested Dictionary Items
There are several ways to remove items from a nested dictionary.
Remove an Item by Key
If you know the key of the item you want, you can use pop() method. It removes the key and returns its value.
D = 'emp1': 'name': 'Bob', 'job': 'Mgr'>, 'emp2': 'name': 'Kim', 'job': 'Dev'>, 'emp3': 'name': 'Sam', 'job': 'Dev'>> x = D.pop('emp3') print(D) # Prints , # 'emp2': > # get removed value print(x) # Prints
If you don’t need the removed value, use the del statement.
D = 'emp1': 'name': 'Bob', 'job': 'Mgr'>, 'emp2': 'name': 'Kim', 'job': 'Dev'>, 'emp3': 'name': 'Sam', 'job': 'Dev'>> del D['emp3'] print(D) # Prints , # 'emp2': >
Remove Last Inserted Item
The popitem() method removes and returns the last inserted item as a tuple.
D = 'emp1': 'name': 'Bob', 'job': 'Mgr'>, 'emp2': 'name': 'Kim', 'job': 'Dev'>, 'emp3': 'name': 'Sam', 'job': 'Dev'>> x = D.popitem() print(D) # Prints , # 'emp2': > # get removed pair print(x) # Prints ('emp3', )
In versions before 3.7, popitem() would remove a random item.
Iterate Through a Nested Dictionary
You can iterate over all values in a nested dictionary using nested for loop.
D = 'emp1': 'name': 'Bob', 'job': 'Mgr'>, 'emp2': 'name': 'Kim', 'job': 'Dev'>, 'emp3': 'name': 'Sam', 'job': 'Dev'>> for id, info in D.items(): print("\nEmployee ID:", id) for key in info: print(key + ':', infoDict get python nested) # Prints Employee ID: emp1 # name: Bob # job: Mgr # Employee ID: emp2 # name: Kim # job: Dev # Employee ID: emp3 # name: Sam # job: Dev
Getting a key’s value in a nested dictionary
I just found a now deleted question on Stack Overflow and solved the problem. The OP was asking for a way to get all the values contained by all ‘PLU’ keys. I solved it this way but because I am a newbie in python I was wondering if it would be an optimal/better way of doing this, maybe using iterators, I don’t know. Result should be:
def getPLU(data): for item in data: if type(data[item]) == dict: getPLU(data[item]) else : if item == 'PLU': print (data[item]) pass def Main(): times = 0 Menu = < 'PLU' : '234', 'Salad': < 'salad': < 'ceaser':< 'PLU': '32' >, 'italian': < 'PLU': '33' >> >, 'Dessert': < 'cookie': < 'PLU': '334', 'NAME': 'cookie ', >>, 'Appetizer': < 'extra sauce': < 'PLU': '61', 'NAME': 'extra sauce', >> > getPLU(data=Menu) #print (getPLU(Menu)) if __name__ == '__main__': Main()
\$\begingroup\$ Thanks for the welcome and thanks for all the answers posted. Also thanks for the corrections made to the question. \$\endgroup\$
4 Answers 4
Great job so far! I have a few suggestions for your code:
- Avoid writing functions with side effects such as printed output. Side effects make a function much less reusable. Instead, you may return a generator that yield s the next entry. This gives the caller maximum control over what to do with the result set: print it, iterate one by one, just get the first few items without searching the entire structure, etc.
- Consider adhering more strictly to Python naming conventions. For example, functions should be lower_camel_cased. Since your function returns multiple PLUs, the function name seems more accurately written as get_plus . You can remove the pass keyword in your function and pay close attention to spacing, for example in the print (data[item]) function call and your else : block.
- Clean up lines like
else : if item == 'PLU': print (data[item])
elif item == 'PLU': print(data[item])
Here’s my version for consideration:
def find_by_key(data, target): for key, value in data.items(): if isinstance(value, dict): yield from find_by_key(value, target) elif key == target: yield value def main(): menu = < 'PLU' : '234', 'Salad': < 'salad': < 'ceaser':< 'PLU': '32' >, 'italian': < 'PLU': '33' >> >, 'Dessert': < 'cookie': < 'PLU': '334', 'NAME': 'cookie ', >>, 'Appetizer': < 'extra sauce': < 'PLU': '61', 'NAME': 'extra sauce', >> > for x in find_by_key(menu, "PLU"): print(x) if __name__ == '__main__': main()
Get value from dictionary given a list of nested keys
I would like to get a deeply-nested value, for example <"a":> by providing the keys to traverse. I tried chaining together .get() but that didn’t work for cases where some of the keys were missing—in those cases, I want to get None instead. Could this solution be improved?"a":
#!/usr/bin/env python # encoding: utf-8 def nestedGet(d,p): if len(p) > 1: try: return nestedGet(d.get(p[0]),p[1:]) except AttributeError: return None if len(p) == 1: try: return d.get(p[0]) except AttributeError: return None print nestedGet(>>,["a","b","c"]) #1 print nestedGet(>>,["a","b","c"]) #None
5 Answers 5
Unless I’m missing something you’d like to implement, I would go for a simple loop instead of using recursion:
def nested_get(input_dict, nested_key): internal_dict_value = input_dict for k in nested_key: internal_dict_value = internal_dict_value.get(k, None) if internal_dict_value is None: return None return internal_dict_value print(nested_get(>>,["a","b","c"])) #1 print(nested_get(>>,["a","b","c"])) #None
I like the following approach that makes use of functools.reduce . It generalizes nicely to other indexable sequences such as lists and tuples.
from functools import reduce def get_nested_item(data, keys): return reduce(lambda seq, key: seqDict get python nested, keys, data)
This can be further simplified by direct access to the __getitem__ method of the sequences, which leads to a noticeable increase in performance (I measured 20-35% for different test data):
from functools import reduce from operator import getitem def get_nested_item(data, keys): return reduce(getitem, keys, data)
get_nested_item(data=>>, keys=["a","b","c"]) # => 1 get_nested_item(data=[[[1,2,3],[10,20,30]]], keys=[0,1,2]) # => 30 get_nested_item(data=, keys=['b',0,1]) # => 2 get_nested_item(data=some_sequence, keys=[]) # => some_sequence
If one prefers soft failure for missing keys/indices, one can catch KeyError or IndexError .
def get_nested_item(data, keys): try: return reduce(getitem, keys, data) except (KeyError, IndexError): return None