2

I am writing a python application where I have a variable dictionary that can be nested upto any level.

The keys in any level can be either int or string. But I want to convert all keys and values at all levels into strings. How nested the dictionary will be is variable which makes it a bit complicated.

{
    "col1": {
        "0": 0,
        "1": 8,
        "2": {
            0: 2,
        }
        "3": 4,
        "4": 5
    },
    "col2": {
        "0": "na",
        "1": 1,
        "2": "na",
        "3": "na",
        "4": "na"
    },
    "col3": {
        "0": 1,
        "1": 3,
        "2": 3,
        "3": 6,
        "4": 3
    },
    "col4": {
        "0": 5,
        "1": "na",
        "2": "9",
        "3": 9,
        "4": "na"
    }
}

I am looking for the shortest and quickest function to achieve that. There are other questions like Converting dictionary values in python from str to int in nested dictionary that suggest ways of doing it but none of them deals with the "variable nesting" nature of the dictionary.

Any ideas will be appreciated.

sshussain270
  • 1,785
  • 4
  • 25
  • 49
  • Something similar https://stackoverflow.com/questions/1254454/fastest-way-to-convert-a-dicts-keys-values-from-unicode-to-str – Rietty Feb 07 '19 at 01:48

3 Answers3

6

This is the most straightforward way I can think of doing it:

import json

data = {'col4': {'1': 'na', '0': 5, '3': 9, '2': '9', '4': 'na'}, 'col2': {'1': 1, '0': 'na', '3': 'na', '2': 'na', '4': 'na'}, 'col3': {'1': 3, '0': 1, '3': 6, '2': 3, '4': 3}, 'col1': {'1': 8, '0': 0, '3': 4, '2': {0: 2}, '4': 5}}
stringified_dict = json.loads(json.dumps(data), parse_int=str, parse_float=str)

Here are some links to the documentation for json loads and parse_int: Python3, Python2

cullzie
  • 2,705
  • 2
  • 16
  • 21
  • 2
    Hey, works great with int, float, "constant" -- not sure what that is, but its not able to convert bool or an array. Any good options for this? Should cover all except bool.. – ScipioAfricanus Nov 15 '19 at 16:39
  • Is there an argument for `parse_path` for working with `pathlib.Path` objects? – Tommy Lees Feb 08 '22 at 22:57
4

You could check the dictionary recursively:

def iterdict(d):
    for k, v in d.items():
        if isinstance(v, dict):
            iterdict(v)
        else:
            if type(v) == int:
                v = str(v)
            d.update({k: v})
    return d

0

In case it's helpful to anyone, I modified Jose's answer to handle lists as well. The output converts all values to strings. I haven't thoroughly tested it, but I just ran it against around 40k records, and it passed schema validation:

def iterdict(d):
    """Recursively iterate over dict converting values to strings."""

    for k, v in d.items():
        if isinstance(v, dict):
            iterdict(v)
        elif isinstance(v, list):
            for x, i in enumerate(v):
                if isinstance(i, (dict, list)):
                    iterdict(i)
                else:
                    if type(i) != str:
                        i = str(i)
                    v[x] = i
        else:
            if type(v) != str:
                v = str(v)
            d.update({k: v})
    return d
dvp
  • 19
  • 7