krizzo
krizzo

Reputation: 1883

Python multilevel dict to strings

I have a python dictionary and a dictionary with in some of the values. I'm trying to generate a dotted delimited string of the keys in the structure with the value at the end. With the example below I'd want FIELD0 1 and NAME. I could create a for loop to process the data or a recursive function. I didn't know if there was something prebuilt method for collapsing a multilevel dictionary to delimited strings?

I was trying the following but as you know it will just append the sub dictionaries.

'.'.join('%s %s\n' % i for i in a.items())

{'BOGUS1': 'BOGUS_VAL1',
 'BOGUS2': 'BOGUS_VAL1',
 'FIELD0': {'F0_VAL1': 1, 'F0_VAL2': 2},
 'FIELD1': {'F1_VAL1': 80, 'F1_VAL2': 67, 'F1_VAL3': 100},
 'FOOBAR1': 'FB_VAL1',
 'NAME': 'VALUE'}

BOGUS2.BOGUS_VAL1
.NAME.VALUE
.BOGUS1.BOGUS_VAL1
.FIELD0.{'F0_VAL1': 1, 'F0_VAL2': 2}
.FIELD1.{'F1_VAL2': 67, 'F1_VAL3': 100, 'F1_VAL1': 80}
.FOOBAR1.FB_VAL1

# Wanted results
FIELD0.F0_VAL1 1
FIELD0.F0_VAL2 2
FIELD1.F1_VAL1 80
FIELD1.F2_VAL1 67
FIELD1.F3_VAL1 100
NAME VALUE

Upvotes: 0

Views: 344

Answers (2)

Hai Vu
Hai Vu

Reputation: 40698

Here is my approach:

def dotted_keys(dic):
    """ Generated dot notation keys from a dictionary """
    queue = [(None, dic)]  # A queue of (prefix, object)
    while queue:
        prefix, current = queue.pop(0)
        for k, v in current.iteritems():
            if isinstance(v, dict):
                queue.append((k, v))
            elif prefix:
                yield prefix + '.' + k
            else:
                yield k


def dict_search(dic, dotted_key, default=None):
    """ Take a dictionary and a dotted key and return the value. If not
    found, return the value specified by the default parameter.

    Example: dict_search(d, 'FIELD0.F0_VAL2')
    """
    current = dic
    keys = dotted_key.split('.')

    for k in keys:
        if k in current:
            current = current[k]
        else:
            return default
    return current


if __name__ == '__main__':
    d = {
        'BOGUS1': 'BOGUS_VAL1',
        'BOGUS2': 'BOGUS_VAL1',
        'FIELD0': {'F0_VAL1': 1, 'F0_VAL2': 2, 'XYZ': {'X1': 9}},
        'FIELD1': {'F1_VAL1': 80, 'F1_VAL2': 67, 'F1_VAL3': 100},
        'FOOBAR1': 'FB_VAL1',
        'NAME': 'VALUE'
    }

    for k in dotted_keys(d):
        print(k, '=', dict_search(d, k))

Output:

BOGUS2 = BOGUS_VAL1
NAME = VALUE
BOGUS1 = BOGUS_VAL1
FOOBAR1 = FB_VAL1
FIELD0.F0_VAL1 = 1
FIELD0.F0_VAL2 = 2
FIELD1.F1_VAL2 = 67
FIELD1.F1_VAL3 = 100
FIELD1.F1_VAL1 = 80
XYZ.X1 = None

The dotted_keys function generates a list of keys in dotted notation while the dict_search function takes a dotted key and return a value.

Upvotes: 1

Yoghurt
Yoghurt

Reputation: 395

How about something like this:

def dotnotation(d, prefix = ''):
    for k, v in d.items():
        if type(v) == type(dict()):
            dotnotation(v, prefix + str(k) + '.')
        else:
            print prefix + str(k) + ' = ' + str(v)

Also the formatting can be changed according to the stored types. This should work with your example.

Upvotes: 1

Related Questions