Add dictionary if key value is empty using python

804 views Asked by At

I have a dictionary with missing values (the key is there, but the associated value is empty). For example I want the dictionary below:

dct = {'ID': '', 'gender': 'male', 'age': '20', 'weight': '', 'height': '5.7'}

to be changed to this form:

dct = {'ID': {'link': '','value': ''}, 'gender': 'male', 'age': '20', 'weight': {'link': '','value': ''}, 'height': '5.7'}

I want the ID and Weight key should be replaced with nested dictionary if its empty.

How can I write that in the most time-efficient way?

I have tried solutions from below links but didnt work,

def update(orignal, addition):
    for k, v in addition.items():
        if k not in orignal:
            orignal[k] = v
        else:
            if isinstance(v, dict):
                update(orignal[k], v)
            elif isinstance(v, list):
                for i in range(len(v)):
                    update(orignal[k][i], v[i])
            else:
                if not orignal[k]:
                    orignal[k] = v

Error: TypeError: 'str' object does not support item assignment

Fill missing keys by comparing example json in python

Adding missing keys in dictionary in Python

2

There are 2 answers

0
binpy On

It seems similar with this issue https://stackoverflow.com/a/3233356/6396981

import collections.abc

def update(d, u):
    for k, v in u.items():
        if isinstance(v, collections.abc.Mapping):
            d[k] = update(d.get(k, {}) or {}, v)
        else:
            d[k] = v
    return d

For example in your case:

>>> dict1 = {'ID':'', 'gender':'male', 'age':'20', 'weight':'', 'height':'5.7'}
>>> dict2 = {'ID': {'link':'','value':''}, 'weight': {'link':'','value':''}}
>>>
>>> update(dict1, dict2)
{'ID': {'link': '', 'value': ''}, 'gender': 'male', 'age': '20', 'weight': {'link': '', 'value': ''}, 'height': '5.7'}
>>>
2
Jay On

You can iterate through the list and see if the value is an empty string('') if it is, replace it with the default value. Here's a small snippet which does it -

dct = {'ID':'', 'gender':'male', 'age':'20', 'weight':'', 'height':'5.7'}

def update(d, default):
    for k, v in d.items():
        if v == '':
            d[k] = default.copy()

update(dct, {'link':'','value':''})
print(dct)

Output :

{'ID': {'link': '', 'value': ''}, 'gender': 'male', 'age': '20', 'weight': {'link': '', 'value': ''}, 'height': '5.7'}

Note that the dict is passed by reference to the function, so any updates made there will be reflected in the original dictionary as well as seen in the above example.


If your dict is nested and you want the replacement to be done for nested items as well then you can use this function -

def nested_update(d, default):
    for k, v in d.items():
        if v == '':
            d[k] = default.copy()
        if isinstance(v, list):
            for item in v:
                nested_update(item, default)
        if isinstance(v, dict):
            nested_update(v, default)

here's a small example with list of dictionaries and nested dictionary -

dct = {'ID':'', 'gender':'male', 'age':'20', 'weight':'', 'height':'5.7', "list_data":[{'empty': ''}, {'non-empty': 'value'}], "nested_dict": {"key1": "val1", "missing_nested": ""}}
nested_update(dct, {'key1': 'val1-added', 'key2': 'val2-added'})
print(dct)

Output :

{'ID': {'key1': 'val1-added', 'key2': 'val2-added'}, 'gender': 'male', 'age': '20', 'weight': {'key1': 'val1-added', 'key2': 'val2-added'}, 'height': '5.7', 'list_data': [{'empty': {'key1': 'val1-added', 'key2': 'val2-added'}}, {'non-empty': 'value'}], 'nested_dict': {'key1': 'val1', 'missing_nested': {'key1': 'val1-added', 'key2': 'val2-added'}}}

For "this default dictionary to only specified keys like ID and Weight and not for other keys", you can update the condition of when we replace the value -

def nested_update(d, default):
    for k, v in d.items():
        if k in ('ID', 'weight') and v == '':
            d[k] = default.copy()
        if isinstance(v, list):
            for item in v:
                nested_update(item, default)
        if isinstance(v, dict):
            nested_update(v, default)