Open In App

Python | Convert nested dictionary into flattened dictionary

Improve
Improve
Like Article
Like
Save
Share
Report

Given a nested dictionary, the task is to convert this dictionary into a flattened dictionary where the key is separated by ‘_’ in case of the nested key to be started.

Method #1: Using Naive Approach 

Step-by-step approach :

  1. The function checks if the input dd is a dictionary. If it is, then it iterates over each key-value pair in the dictionary, and calls the flatten_dict function recursively on the value of each key. It concatenates the original key and the returned key from the recursive call with the separator, and uses that as the new key in the flattened dictionary. It sets the value of the new key to the returned value from the recursive call.
  2. If the input dd is not a dictionary, the function creates a new dictionary with a single key-value pair, where the key is the prefix argument (which is the path to the current value in the original nested dictionary), and the value is the input dd itself.
  3. The code then initializes a nested dictionary ini_dict with some sample data.
  4. The code prints the initial dictionary ini_dict.
  5. The code calls the flatten_dict function on the ini_dict dictionary and prints the resulting flattened dictionary.

Python3




# Python code to demonstrate
# conversion of nested dictionary
# into flattened dictionary
 
# code to convert ini_dict to flattened dictionary
# default separator '_'
def flatten_dict(dd, separator ='_', prefix =''):
    return { prefix + separator + k if prefix else k : v
             for kk, vv in dd.items()
             for k, v in flatten_dict(vv, separator, kk).items()
             } if isinstance(dd, dict) else { prefix : dd }
         
# initialising_dictionary
ini_dict = {'geeks': {'Geeks': {'for': 7}},
            'for': {'geeks': {'Geeks': 3}},
            'Geeks': {'for': {'for': 1, 'geeks': 4}}}
 
# printing initial dictionary
print ("initial_dictionary", str(ini_dict))
 
 
# printing final dictionary
print ("final_dictionary", str(flatten_dict(ini_dict)))


Output: 
initial_dictionary {‘geeks’: {‘Geeks’: {‘for’: 7}}, ‘Geeks’: {‘for’: {‘geeks’: 4, ‘for’: 1}}, ‘for’: {‘geeks’: {‘Geeks’: 3}}} 
final_dictionary {‘Geeks_for_for’: 1, ‘geeks_Geeks_for’: 7, ‘for_geeks_Geeks’: 3, ‘Geeks_for_geeks’: 4} 
 

Time complexity: O(n^2), where n is the total number of keys in the nested dictionary.
Auxiliary space: O(n), where n is the total number of keys in the nested dictionary. The auxiliary space is used to store the result of the flatten dictionary in the form of a new dictionary.

Method #2: Using mutableMapping 

Python3




# Python code to demonstrate
# conversion of nested dictionary
# into flattened dictionary
 
from collections import MutableMapping
 
# code to convert ini_dict to flattened dictionary
# default separator '_'
def convert_flatten(d, parent_key ='', sep ='_'):
    items = []
    for k, v in d.items():
        new_key = parent_key + sep + k if parent_key else k
 
        if isinstance(v, MutableMapping):
            items.extend(convert_flatten(v, new_key, sep = sep).items())
        else:
            items.append((new_key, v))
    return dict(items)
         
# initialising_dictionary
ini_dict = {'geeks': {'Geeks': {'for': 7}},
            'for': {'geeks': {'Geeks': 3}},
            'Geeks': {'for': {'for': 1, 'geeks': 4}}}
 
# printing initial dictionary
print ("initial_dictionary", str(ini_dict))
 
 
# printing final dictionary
print ("final_dictionary", str(convert_flatten(ini_dict)))


Output: 
initial_dictionary {‘Geeks’: {‘for’: {‘for’: 1, ‘geeks’: 4}}, ‘for’: {‘geeks’: {‘Geeks’: 3}}, ‘geeks’: {‘Geeks’: {‘for’: 7}}} 
final_dictionary {‘Geeks_for_geeks’: 4, ‘for_geeks_Geeks’: 3, ‘geeks_Geeks_for’: 7, ‘Geeks_for_for’: 1} 
 

Time Complexity: O(n)
Auxiliary Space: O(n)

Method #3: Using Python Generators  

Python3




# Python code to demonstrate
# conversion of nested dictionary
# into flattened dictionary
 
my_map = {"a" : 1,
        "b" : {
            "c": 2,
            "d": 3,
            "e": {
                "f":4,
                6:"a",
                5:{"g" : 6},
                "l":[1,"two"]
            }
        }}
 
# Expected Output
# {'a': 1, 'b_c': 2, 'b_d': 3, 'b_e_f': 4, 'b_e_6': 'a', 'b_e_5_g': 6, 'b_e_l': [1, 'two']}
 
 
ini_dict = {'geeks': {'Geeks': {'for': 7}},
            'for': {'geeks': {'Geeks': 3}},
            'Geeks': {'for': {'for': 1, 'geeks': 4}}}
 
# Expected Output
# {‘Geeks_for_geeks’: 4, ‘for_geeks_Geeks’: 3, ‘Geeks_for_for’: 1, ‘geeks_Geeks_for’: 7}
 
def flatten_dict(pyobj, keystring=''):
    if type(pyobj) == dict:
        keystring = keystring + '_' if keystring else keystring
        for k in pyobj:
            yield from flatten_dict(pyobj[k], keystring + str(k))
    else:
        yield keystring, pyobj
 
print("Input : %s\nOutput : %s\n\n" %
     (my_map, { k:v for k,v in flatten_dict(my_map) }))
 
print("Input : %s\nOutput : %s\n\n" %
     (ini_dict, { k:v for k,v in flatten_dict(ini_dict) }))


Output: 
initial_dictionary {‘for’: {‘geeks’: {‘Geeks’: 3}}, ‘geeks’: {‘Geeks’: {‘for’: 7}}, ‘Geeks’: {‘for’: {‘for’: 1, ‘geeks’: 4}}} 
final_dictionary {‘Geeks_for_geeks’: 4, ‘for_geeks_Geeks’: 3, ‘Geeks_for_for’: 1, ‘geeks_Geeks_for’: 7} 
 

Time complexity: O(n), where n is the total number of keys in the nested dictionary
Auxiliary space: O(n), where n is the total number of keys in the nested dictionary. 

Method #4: Using recursion and a separator

  1. Define a function “flatten_dict” that takes in three parameters: dd (a dictionary), separator (a string, default value “_”), and prefix (a string, default value “”).
  2. Initialize an empty dictionary “res”.
  3. Iterate through each key-value pair in the dictionary “dd”.
  4. Check if the value associated with the current key is itself a dictionary or not. If it is a dictionary, then recursively call the “flatten_dict” function with the value as the new dictionary to be flattened, the separator and prefix updated with the current key and separator value.
  5. If the value is not a dictionary, then add the key-value pair to the “res” dictionary, where the key is the concatenation of prefix, separator and current key.
  6. Return the final “res” dictionary.

Python3




# code to convert ini_dict to flattened dictionary
def flatten_dict(dd, separator='_', prefix=''):
    res = {}
    for key, value in dd.items():
        if isinstance(value, dict):
            res.update(flatten_dict(value, separator, prefix + key + separator))
        else:
            res[prefix + key] = value
    return res
 
# initialising_dictionary
ini_dict = {'geeks': {'Geeks': {'for': 7}},
            'for': {'geeks': {'Geeks': 3}},
            'Geeks': {'for': {'for': 1, 'geeks': 4}}}
 
# printing initial dictionary
print("initial dictionary", str(ini_dict))
 
# flattening the dictionary
res = flatten_dict(ini_dict)
 
# printing final dictionary
print("final dictionary", str(res))
#This code is contributed by Vinay Pinjala.


Output

initial dictionary {'geeks': {'Geeks': {'for': 7}}, 'for': {'geeks': {'Geeks': 3}}, 'Geeks': {'for': {'for': 1, 'geeks': 4}}}
final dictionary {'geeks_Geeks_for': 7, 'for_geeks_Geeks': 3, 'Geeks_for_for': 1, 'Geeks_for_geeks': 4}

The time complexity of this algorithm is O(N), where N is the total number of keys in the nested dictionary. This is because the algorithm iterates through each key exactly once.
The space complexity is also O(N), where N is the total number of keys, since the algorithm creates a new dictionary “res” to store the flattened dictionary.

Method 5: Using a stack data structure

The idea is to iterate through the dictionary and push all nested dictionaries into a stack. Then, we can pop each dictionary from the stack, iterate through its key-value pairs, and append the key-value pairs to a flattened dictionary.

  1. Initialize an empty stack.
  2. Push the initial dictionary onto the stack.
  3. Initialize an empty flattened dictionary.
  4. While the stack is not empty, do the following:
    a. Pop the top dictionary from the stack.
    b. For each key-value pair in the popped dictionary, do the following:
    i. If the value is a dictionary, push it onto the stack with its key as the prefix.
    ii. Otherwise, add the key-value pair to the flattened dictionary with the prefix and separator (default is ‘_’).
  5. Return the flattened dictionary.

Python3




# code to convert ini_dict to flattened dictionary using stack data structure
def flatten_dict(dd, separator='_', prefix=''):
    stack = [(dd, prefix)]
    flat_dict = {}
     
    while stack:
        cur_dict, cur_prefix = stack.pop()
        for key, val in cur_dict.items():
            new_key = cur_prefix + separator + key if cur_prefix else key
            if isinstance(val, dict):
                stack.append((val, new_key))
            else:
                flat_dict[new_key] = val
                 
    return flat_dict
 
# initialising_dictionary
ini_dict = {'geeks': {'Geeks': {'for': 7}},
            'for': {'geeks': {'Geeks': 3}},
            'Geeks': {'for': {'for': 1, 'geeks': 4}}}
 
# printing initial dictionary
print("initial_dictionary", str(ini_dict))
 
# printing final dictionary
print("final_dictionary", str(flatten_dict(ini_dict)))


Output

initial_dictionary {'geeks': {'Geeks': {'for': 7}}, 'for': {'geeks': {'Geeks': 3}}, 'Geeks': {'for': {'for': 1, 'geeks': 4}}}
final_dictionary {'Geeks_for_for': 1, 'Geeks_for_geeks': 4, 'for_geeks_Geeks': 3, 'geeks_Geeks_for': 7}

Time complexity: O(n), where n is the total number of key-value pairs in the input nested dictionary.
Auxiliary space: O(n), where n is the total number of key-value pairs in the input nested dictionary.

Method 6: Using a recursive function without a separator

Here is an alternative method that uses a recursive function without a separator. It works by iterating over the items of the dictionary and checking whether each value is another dictionary. If it is, the function calls itself recursively and concatenates the key with the new keys returned by the recursive call. If it is not, the function simply adds the key-value pair to the result dictionary.

Here’s the step by step approach:

  1. Define a function called flatten_dict_recursive that takes a dictionary d as input.
  2. Initialize an empty dictionary called result.
  3. For each key-value pair in d, do the following:
    a. If the value is a dictionary, call flatten_dict_recursive with the value and concatenate the returned keys with the current key.
    b. If the value is not a dictionary, add the current key and value to result.
  4. Return result.

Python3




def flatten_dict(dd, separator='_', prefix=''):
    stack = [(dd, prefix)]
    flat_dict = {}
     
    while stack:
        cur_dict, cur_prefix = stack.pop()
        for key, val in cur_dict.items():
            new_key = cur_prefix + separator + key if cur_prefix else key
            if isinstance(val, dict):
                stack.append((val, new_key))
            else:
                flat_dict[new_key] = val
                 
    return flat_dict
 
# initialising_dictionary
ini_dict = {'geeks': {'Geeks': {'for': 7}},
            'for': {'geeks': {'Geeks': 3}},
            'Geeks': {'for': {'for': 1, 'geeks': 4}}}
 
# printing initial dictionary
print("initial_dictionary", str(ini_dict))
 
# printing final dictionary
print("final_dictionary", str(flatten_dict(ini_dict, separator='')))


Output

initial_dictionary {'geeks': {'Geeks': {'for': 7}}, 'for': {'geeks': {'Geeks': 3}}, 'Geeks': {'for': {'for': 1, 'geeks': 4}}}
final_dictionary {'Geeksforfor': 1, 'Geeksforgeeks': 4, 'forgeeksGeeks': 3, 'geeksGeeksfor': 7}

Time complexity: The time complexity of this function is O(n), where n is the total number of key-value pairs in the dictionary. 

Auxiliary space: The auxiliary space complexity of this function is O(n), where n is the total number of key-value pairs in the dictionary. 



Last Updated : 04 Apr, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads