licorna
licorna

Reputation: 5880

Recursive iteration and modification of dict

I have a JSON file like this:

{
    "top_key1": {
                "bottom.key1": "one",
                "bottom.key2": "two"
                },
    "top_key2": [
                "bottom.key1": "one",
                "bottom.key2": "two",
                ]
}

And I need to store in a data structure that won't allow me to store a key with a period (.) on it. How can I traverse this JSON structure so I replace every . occurrence by _? The final result would be:

{
    "top_key1": {
                "bottom_key1": "one",
                "bottom_key2": "two"
                },
    "top_key2": [
                "bottom_key1": "one",
                "bottom_key2": "two",
                ]
}

The JSON file can be nested several (unknown) times and there can be . on values also, but I don't want them replaced by _. Also, value of "top_key2" is a list, which should be preserved.

Upvotes: 1

Views: 79

Answers (1)

Marius
Marius

Reputation: 60160

Not too hard I think, just use isinstance to check if the current value is another dict:

nested_dict = {
    "top_key1": {
                "bottom.key1": "one",
                "bottom.key2": "two"
                },
    "top_key2": {
                "bottom.key1": "one",
                "bottom.key2": "two",
                }
}

def replace_dots(nested_dict):
    result_dict = {}
    for key, val in nested_dict.items():
        key = key.replace('.', '_')
        if isinstance(val, dict):
            result_dict[key] = replace_dots(val)
        else:
            result_dict[key] = val
    return result_dict

fixed = replace_dots(nested_dict)

fixed
Out[4]: 
{'top_key1': {'bottom_key1': 'one', 'bottom_key2': 'two'},
 'top_key2': {'bottom_key1': 'one', 'bottom_key2': 'two'}}

I'm not sure if I fully understand your edit, as your example list still has a key-value structure, but adding an extra case to deal with lists is pretty simple:

nested_dict2 = {
    "top_key1": {
                "bottom.key1": "one",
                "bottom.key2": "two"
                },
    "top_key2": ["list.item1", "list.item2"]
}

def replace_dots(nested_dict):
    result_dict = {}
    for key, val in nested_dict.items():
        key = key.replace('.', '_')
        if isinstance(val, dict):
            result_dict[key] = replace_dots(val)
        elif isinstance(val, list):
            cleaned_val = [v.replace('.', '_') for v in val]
            result_dict[key] = cleaned_val
        else:
            result_dict[key] = val
    return result_dict

replace_dots(nested_dict2)
Out[7]: 
{'top_key1': {'bottom_key1': 'one', 'bottom_key2': 'two'},
 'top_key2': ['list_item1', 'list_item2']}

Upvotes: 3

Related Questions