MaxGeneGrim
MaxGeneGrim

Reputation: 203

Python recursivly print a nested hash

I would like to print nested hash in Python, from this:

example_dict = {
    'key1' : 'value1',
    'key2' : {
        'key2a': 'value2a'
    },
    'key3' : {
        'key3a': {
            'key3aa': 'value3aa',
            'key3ab': 'value3ab',
            'key3ac': 'value3ac'
        },
        'key3b': [
            'value3b1',
            'value3b2'
        ]
    },
}

to something like this:

key1 value1
key2 key2a value2a
key3 key3a key3aa value3aa
key3 key3a key3ab value3ab
key3 key3a key3ac value3ac
key3 key3b value3b1
key3 key3b value3b2

I am not really familiar with Python, and after couple hours I'm still stuck.

I currently working on this function:

def recursive(src, res, line = ''):
    if isinstance(src, dict):
        for key, value in src.items():
            line += str(' ' + key)
            recursive(value, res, line)
    elif isinstance(src, list):
        for litem in src:
            recursive(litem, res, line)
    else:
        line += str(' ' + str(src))
        res.append(line)

I'm trying to add each line to a list to be able to use it later, but I think I don't have the right aproach with my shared variable (line), because at each dict the recursive call is made with one more dict key from the same level of depth, so I got this :

 key3 key3a key3aa value3aa
 key3 key3a key3aa key3ac value3ac
 key3 key3a key3aa key3ac key3ab value3ab
 key3 key3a key3b value3b1
 key3 key3a key3b value3b2
 key3 key2 key2a value2a
 key3 key2 key1 value1

What would be a Pythonic way to do this?

Upvotes: 1

Views: 90

Answers (3)

Stephen Rauch
Stephen Rauch

Reputation: 49814

Using a generator (yield statement) you can do that recursively like:

Code:

def recursive(src, so_far=()):
    if isinstance(src, dict):
        for key, value in src.items():
            yield from recursive(value, so_far + (key,))
    elif isinstance(src, list):
        for item in src:
            yield from recursive(item, so_far)
    else:
        yield ' '.join(so_far + (src,))

One thing to note is the need to re-yield the results from the generator that was recursed into. That is done here using:

yield from recursive(item, so_far)

Which is equivalent to:

for i in recursive(item, so_far):
    yield i

Test Code:

example_dict = {
    'key1': 'value1',
    'key2': {
        'key2a': 'value2a'
    },
    'key3': {
        'key3a': {
            'key3aa': 'value3aa',
            'key3ab': 'value3ab',
            'key3ac': 'value3ac'
        },
        'key3b': [
            'value3b1',
            'value3b2'
        ]
    },
}

for line in recursive(example_dict):
    print(line)

Results:

key1 value1
key2 key2a value2a
key3 key3a key3aa value3aa
key3 key3a key3ab value3ab
key3 key3a key3ac value3ac
key3 key3b value3b1
key3 key3b value3b2

Upvotes: 7

xrisk
xrisk

Reputation: 3898

Pretty straightforward recursive implementation.

def pr(t, pref=''):
    for k, v in t.items():
        if isinstance(v, dict):
            pr(v, pref=(pref + k + ' '))
        elif isinstance(v, list):
            for el in v:
                if isinstance(el, str):
                    print(pref + ' ' + k + ' ' + el)
                else:
                    pr(el, pref=k + ' ')
        else:
            print(pref + ' ' + k + ' ' + v)

Upvotes: 0

ktzr
ktzr

Reputation: 1645

I got this to work, but its a bit hacky, using append adds one element, and extend adds all elements in a list. Hope it helps:

def recursive(src, start=""):
    lst = []
    for k, v in src.items():
        new_start = "{} {}".format(start, k)
        if isinstance(v, dict):
            lst.extend(recursive(v, start=new_start))
        elif isinstance(v, list):
            lst.extend("{}: {}".format(new_start[1:] , val) for val in v)
        else:
            lst.append("{}: {}".format(new_start[1:] , v))

    return lst


items = recursive(example_dict)
for item in items:
    print(item)

Output:

 key1: value1
 key2 key2a: value2a
 key3 key3a key3aa: value3aa
 key3 key3a key3ab: value3ab
 key3 key3a key3ac: value3ac
 key3 key3b: value3b1
 key3 key3b: value3b2

Upvotes: 1

Related Questions