Search code examples
pythonstringdictionaryfor-loopdictionary-comprehension

Convert keys of a nested dictionary to upper case


Have a dictionary:

data = {'Common': {'height': 165, 'weight': 70, 'measure': ['cm', 'kg']},
         'Man': 'handsome',
         'Woman': {'feature': 'pretty', 'weight': 50},
         'Dog': {'feature': 'barks', 'height': 10, 'weight': 20}}

Would like to convert only dictionary keys to UPPERCASE.

Tried the following code:

d = {}
d1 = {}
for k, v in data.items():
    if isinstance(v, dict):
        for i, j in v.items():
            d1[i.upper()] = j
        d[k.upper()] = d1
    else:
        d[k.upper()] = v

print(d)

...which produces the output with unnecessary keys and height and weight rationalization as follows:

{'COMMON': {'HEIGHT': 10, 'WEIGHT': 20, 'MEASURE': ['cm', 'kg'], 'FEATURE': 'barks'}, 
    'MAN': 'handsome', 
  'WOMAN': {'HEIGHT': 10, 'WEIGHT': 20, 'MEASURE': ['cm', 'kg'], 'FEATURE': 'barks'}, 
    'DOG': {'HEIGHT': 10, 'WEIGHT': 20, 'MEASURE': ['cm', 'kg'], 'FEATURE': 'barks'}}

My expected output is:

{'COMMON': {'HEIGHT': 165, 'WEIGHT': 70, 'MEASURE': ['cm', 'kg']},
 'MAN': 'handsome',
 'WOMAN': {'FEATURE': 'pretty', 'WEIGHT': 50},
 'DOG': {'FEATURE': 'barks', 'HEIGHT': 10, 'WEIGHT': 20}}
  1. Where am I going wrong?
  2. What is the correct dictionary comprehension like {{i.upper(): j} if isinstance(j, dict) else {k.upper(): v} for k, v in data.items() for i, j in v.items()}?

Solution

  • The issue with your code is that you are reassigning d1 if the value is a dictionary. You can solve this by using copy.deepcopy():

    Code:

    from copy import deepcopy
    
    d = {}
    d1 = {}
    for k, v in data.items():
        if isinstance(v, dict):
            for i, j in v.items():
                d1[i.upper()] = j
            d[k.upper()] = deepcopy(d1)
        else:
            d[k.upper()] = v
    

    Output:

    >>> d
    {'COMMON': {'HEIGHT': 165, 'WEIGHT': 70, 'MEASURE': ['cm', 'kg']},
     'MAN': 'handsome',
     'WOMAN': {'FEATURE': 'pretty', 'WEIGHT': 50},
     'DOG': {'FEATURE': 'barks', 'HEIGHT': 10, 'WEIGHT': 20}}
    

    Alternatively, as a dictionary comprehension:

    >>> {k.upper(): {i.upper(): j for i, j in v.items()} if isinstance(v, dict) else v for k, v in data.items()}
    {'COMMON': {'HEIGHT': 165, 'WEIGHT': 70, 'MEASURE': ['cm', 'kg']},
     'MAN': 'handsome',
     'WOMAN': {'FEATURE': 'pretty', 'WEIGHT': 50},
     'DOG': {'FEATURE': 'barks', 'HEIGHT': 10, 'WEIGHT': 20}}