Dictionary comprehension for swapping keys/values

2019-09-04 14:18发布

问题:

def invert_dict(d):
    inv = dict()
    for key in d:
        val = d[key]
        if val not in inv:
            inv[val] = [key]
        else:
            inv[val].append(key)
return inv

This is an example from Think Python book, a function for inverting(swapping) keys and values in a dictionary. New values (former keys) are stored as lists, so if there was multiple dictionary values (bound to a different keys) that were equal before inverting, then this function simply appends them to the list of former keys.

Example:

somedict = {'one': 1, 'two': 2, 'doubletwo': 2, 'three': 3}
invert_dict(somedict) ---> {1: ['one'], 2: ['doubletwo', 'two'], 3: ['three']}

My question is, can the same be done with dictionary comprehensions? This function creates an empty dict inv = dict(), which is then checked later in the function with if/else for the presence of values. Dict comprehension, in this case, should check itself. Is that possible, and how the syntax should look like?

General dict comprehension syntax for swapping values is:

{value:key for key, value in somedict.items()}

but if I want to add an 'if' clausule, what it should look like? if value not in (what)?

Thanks.

回答1:

You can use a set comprehension side effect:

somedict = {'one': 1, 'two': 2, 'doubletwo': 2, 'three': 3}

invert_dict={}
{invert_dict.setdefault(v, []).append(k) for k, v in somedict.items()}

print invert_dict
# {1: ['one'], 2: ['doubletwo', 'two'], 3: ['three']}


回答2:

I don't think it's possible with simple dict comprehension without using other functions.

Following code uses itertools.groupby to group keys that have same values.

>>> import itertools
>>> {k: [x[1] for x in grp]
     for k, grp in itertools.groupby(
         sorted((v,k) for k, v in somedict.iteritems()),
         key=lambda x: x[0])
    }
{1: ['one'], 2: ['doubletwo', 'two'], 3: ['three']}