1

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?

3 Answers 3

7

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
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the nice answer. I wonder if it would be worth mentioning the yield from construct in the context of the two for ...: yield... blocks?
Thanks for the answer and for the links, that helps a lot ! I also looking at the yield from as mentioned above by curiosity, but your solution works like a charm in my case. Again Thank you !
1

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

Comments

0

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)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.