Lucas Mengual
Lucas Mengual

Reputation: 415

Flatten dictionary with nested keys and array

I need help with a function to flatten a nested dictionary in the following format:

dict_test = {
    "subdoc": {
        "a": 1,
        "b": 2,
        "c": 3,
        "array": [
            {"name": "elmo"},
            {"name": "oscar"}
        ]
    }
}

I tried the function below, but is doesn´t flatten the nested keys inside the array element.

def flatten_dict(dd, separator='.', prefix=''):
    return { prefix + separator + k if prefix else k : v
             for kk, vv in dd.items()
             for k, v in flatten_dict(vv, separator, kk).items()
             } if isinstance(dd, dict) else { prefix : dd }

My current output is:

{'subdoc.a': 1,
 'subdoc.b': 2,
 'subdoc.c': 3,
 'subdoc.array': [{'name': 'elmo'}, {'name': 'oscar'}]}

But actually I´m looking something like:

{
    "subdoc.a": 1,
    "subdoc.b": 2,
    "subdoc.c": 3,
    "subdoc.array.0.name": "elmo",
    "subdoc.array.1.name": "oscar"
}

Upvotes: 0

Views: 149

Answers (1)

Lior Cohen
Lior Cohen

Reputation: 5735

dict_test = {
    "subdoc": {
        "a": 1,
        "b": 2,
        "c": 3,
        "array": [
            {"name": "elmo"},
            {"name": "oscar"}
        ]
    }
}

def flatten(d):
    agg = {}
    def _flatten(d, prev_key=''):
        if isinstance(d, list):
            for i, item in enumerate(d):
                new_k = '%s.%s' % (prev_key, i) if prev_key else i
                _flatten(item, prev_key=new_k)
        elif isinstance(d, dict):
            for k, v in d.items():
                new_k = '%s.%s' % (prev_key, k) if prev_key else k
                _flatten(v, prev_key=new_k)
        else:
            agg[prev_key] = d

    _flatten(d)
    return agg


print(flatten(dict_test))
# gives {'subdoc.a': 1, 'subdoc.b': 2, 'subdoc.c': 3, 'subdoc.array.0.name': 'elmo', 'subdoc.array.1.name': 'oscar'}

Note: only tested for your case

Upvotes: 1

Related Questions