Python Forum

Full Version: complicated dict comprehension
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
# Initial dictionary
d = {
    'one': 'some val',
    'two': 'some val',
    'three': {
        'subkey_1': 'some val',
        'subkey_2': 'some val'
        },
    'four': 'some val',
    'five': {
        'subkey_1': 'some val',
        'subkey_2': 'some val'
        },
    'six': 'some val'
}

# This results in the dictionary that I want:
new = {}
for k, v in d.items():
    if not isinstance(v, dict):
        new[k] = v
    else:
        for i, j in v.items():
            new['%s_%s' % (k, i)] = j
print(new)


# example correct output:
# {
#     'one': 'some val',
#     'two': 'some val',
#     'three_subkey_1': 'some val',
#     'three_subkey_2': 'some val',
#     'four': 'some val',
#     'five_subkey_1': 'some val',
#     'five_subkey_2': 'some val',
#     'six': 'some val'
# }


# But can this be done in a dict comprehension?
# I am trying this:

new = {k: v if not isinstance(v, dict) else {i['%s_%s' % (k, i)]: j for i, j in v.items()} for k, v in d.items()}
print(new)

# But I suspect that inner dictionary needs to be unpacked somehow? Is this possible? Maybe with another technique?
Quote:>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.

Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
The first version is better. I like "yield" and reusable functions so I would write this
d = {
    'one': 'some val',
    'two': 'some val',
    'three': {
        'subkey_1': 'some val',
        'subkey_2': 'some val'
        },
    'four': 'some val',
    'five': {
        'subkey_1': 'some val',
        'subkey_2': 'some val'
        },
    'six': 'some val'
}

def subitems(d):
    for key, value in d.items():
        if isinstance(value, dict):
            for subkey, subvalue in value.items():
                yield f"{key}_{subkey}", subvalue
        else:
            yield key, value
            
new = dict(subitems(d))
print(new)
Hmmm okay. I was wondering if possible to do the unreadable one-liner haha. Thanks
You can do pretty much anything in one liners. Especially list ocmps in combination with the use of the semicolon to separate statements on one line. But the time it takes to make them and decipher them is not worth the hassle.