Given a dictionary with keys joined by a split character, the task is to write a Python program to turn the dictionary into nested and grouped dictionaries.
Examples
Input: test_dict = {“1-3” : 2, “1-8” : 10}, splt_chr = “-“
Output: {‘1’: {‘3’: 2, ‘8’: 10}}
Explanation : 1 is linked to 3 with value 2 and 8 with value 10, hence those elements are nested and values assigned.Input: test_dict = {“1-3” : 2, “8-7” : 0, “1-8” : 10, “8-6” : 15}, splt_chr = “-“
Output: {‘1’: {‘3’: 2, ‘8’: 10}, ‘8’: {‘7’: 0, ‘6’: 15}}
Explanation : 1 is linked to 3 with value 2 and 8 with value 10, similarly 8 is linked to 7 with value 0 and 6 with value 15, hence those elements are nested and values assigned.
Method #1 : Using loop + split()
In this, we perform the task of splitting the keys for flattening using split(). And then memorization of keys is done using dictionary which adds to its nested dictionaries other similar nested keys found.
Python3
# Python3 code to demonstrate working of # Group Hierarchy Splits of keys in Dictionary # Using loop + split() # initializing dictionary test_dict = { "1-3" : 2 , "8-7" : 0 , "1-8" : 10 , "8-6" : 15 } # printing original dictionary print ( "The original dictionary is : " + str (test_dict)) # initializing split char splt_chr = "-" res = dict () for key, val in test_dict.items(): ini_key, low_key = key.split(splt_chr) # check if key already present if ini_key not in res: res[ini_key] = dict () # add nested value if present key res[ini_key][low_key] = val # printing result print ( "The splitted dictionary : " + str (res)) |
The original dictionary is : {'1-3': 2, '8-7': 0, '1-8': 10, '8-6': 15} The splitted dictionary : {'1': {'3': 2, '8': 10}, '8': {'7': 0, '6': 15}}
Method #2 : Using defaultdict()
Similar to the above method, the Only difference being defaultdict() is used for the task of memorizing the grouping keys.
Python3
# Python3 code to demonstrate working of # Group Hierarchy Splits of keys in Dictionary # Using defaultdict() from collections import defaultdict # initializing dictionary test_dict = { "1-3" : 2 , "8-7" : 0 , "1-8" : 10 , "8-6" : 15 } # printing original dictionary print ( "The original dictionary is : " + str (test_dict)) # initializing split char splt_chr = "-" res = defaultdict( dict ) for key, val in test_dict.items(): ini_key, low_key = key.split(splt_chr) # defaultdict eliminates check step res[ini_key][low_key] = val # printing result print ( "The splitted dictionary : " + str ( dict (res))) |
The original dictionary is : {'1-3': 2, '8-7': 0, '1-8': 10, '8-6': 15} The splitted dictionary : {'1': {'3': 2, '8': 10}, '8': {'7': 0, '6': 15}}
Method #3: Using recursive function
Approach
using a recursive function to split the keys and create nested dictionaries based on the split parts. The function takes in a list of keys and a value and creates a nested dictionary based on the split parts of the keys.
Algorithm
1. Initialize an empty dictionary called result.
2. Define a recursive function called add_to_dict that takes in a list of keys and a value.
3. If the list of keys is empty, return the value.
4. Otherwise, pop the first key from the list and create a nested dictionary based on the remaining keys and the value.
5. Add the nested dictionary to the result dictionary.
6. Call the add_to_dict function recursively with the remaining keys and the nested dictionary.
7. Return the result dictionary.
Python3
def group_hierarchy_split2(test_dict, splt_chr): result = {} for key in test_dict: key_parts = key.split(splt_chr) inner_dict = add_to_dict(key_parts[ 1 :], test_dict[key]) result.setdefault(key_parts[ 0 ], {}).update(inner_dict) return result def add_to_dict(keys, value): if not keys: return value key = keys.pop( 0 ) return {key: add_to_dict(keys, value)} test_dict = { "1-3" : 2 , "8-7" : 0 , "1-8" : 10 , "8-6" : 15 } splt_chr = "-" print (group_hierarchy_split2(test_dict, splt_chr)) |
{'1': {'3': 2, '8': 10}, '8': {'7': 0, '6': 15}}
Time complexity: O(nm) where n is the number of keys in the input dictionary and m is the maximum length of a key.
Auxiliary Space: O(nm) where n is the number of keys in the input dictionary and m is the maximum length of a key.
Method 4: Using itertools.groupby()
Step-by-step approach:
Import the groupby function from the itertools module.
Initialize the dictionary test_dict.
Print the original dictionary.
Initialize the split character splt_chr.
Use the groupby() function to group the keys in test_dict based on the first element of each key.
Sort the keys of test_dict before grouping to ensure that the groups are contiguous.
For each group of keys, create a nested dictionary with the second element of each key as the inner key and the corresponding value from test_dict as the inner value.
Use a dictionary comprehension to create a new dictionary with the grouped dictionaries as the inner dictionaries, and the first element of each key as the outer key.
Print the resulting dictionary.
Python3
# importing groupby from itertools from itertools import groupby # initializing dictionary test_dict = { "1-3" : 2 , "8-7" : 0 , "1-8" : 10 , "8-6" : 15 } # printing original dictionary print ( "The original dictionary is : " + str (test_dict)) # initializing split char splt_chr = "-" # group the keys based on the first element using groupby() grouped_keys = groupby( sorted (test_dict.keys()), lambda x: x.split(splt_chr)[ 0 ]) # create a new dictionary with nested dictionaries res = {k: {x.split(splt_chr)[ 1 ]: test_dict[x] for x in v} for k, v in grouped_keys} # printing result print ( "The splitted dictionary : " + str (res)) |
The original dictionary is : {'1-3': 2, '8-7': 0, '1-8': 10, '8-6': 15} The splitted dictionary : {'1': {'3': 2, '8': 10}, '8': {'6': 15, '7': 0}}
Time complexity: O(nlogn), where n is the number of key-value pairs in the dictionary due to sorting the keys.
Auxiliary space: O(n), where n is the number of key-value pairs in the dictionary.