Benjamin James
Benjamin James

Reputation: 961

Convert dict with mixed values to flat dict

I would like to iterate through a dict whose values are a mixture of lists, unicode strings, dicts, bools, and ints to produce a one-dimensional dict that has all key-value pairs. I don't care to preserve keys whose associated values are dicts.

I tried a recursive function but I am missing some steps. Perhaps I need to use .update() or += somewhere?

def unravel(data):
    resultsdict = {}
    for k in data:
        if isinstance(data[k],dict):
            unravel(data[k])
        else:
            resultsdict[k] = data[k]  

Example of my top-level dict's values:

<type 'list'>
<type 'bool'>
<type 'dict'>
<type 'unicode'>
<type 'bool'>
<type 'unicode'>
<type 'dict'>
<type 'int'>
<type 'unicode'>

Upvotes: 1

Views: 291

Answers (3)

jfbeltran
jfbeltran

Reputation: 1818

You can just unpack all the dictionary tuples and then flatten the whole thing

# Turn every key,value pair into a list of tuples 
# [(key, value)] if it's any datatype but dict
# value.iteritems() otherwise
grouped_key_value_pairs = [v.iteritems() if isinstance(v,dict) else [(k,v)] for k,v in data.iteritems()]

# Flatten into a single list of tuples and turn into dict!
result = dict([kv_pair for group in all_kv_pairs for kv_pair in group])

Upvotes: 0

poke
poke

Reputation: 387647

You were almost there, you need to return the created dictionary though, and update the dictionary with the returned value from the recursive call:

def unravel (data):
    d = {}
    for k, v in data.items():
        if isinstance(v, dict):
            d.update(unravel(v))
        else:
            d[k] = v
    return d

Used like this:

>>> unravel({ 'a': { 'b': 'c', 'd': 'e' }, 'f': 'g', 'h': { 'i': 'j' } })
{'f': 'g', 'i': 'j', 'b': 'c', 'd': 'e'}

Upvotes: 4

th3an0maly
th3an0maly

Reputation: 3510

Your method unravel creates a new instance of resultsdict every time you recursively call it. Hence, not all data is getting into the master dictionary (so to speak). Try something like this instead:

def unravel(data, resultsdict={}):
    for k in data:
        if isinstance(data[k],dict):
            unravel(data[k], resultsdict)
        else:
            resultsdict[k] = data[k]
    return resultsdict

In recursion scenarios such as this, you should keep carrying the mutable datastructure with you every time you recurse.

Upvotes: 1

Related Questions