简体   繁体   中英

How do I reverse this dictionary in the format given?

I want to convert this:

d={'move': ['liikuttaa'], 'hide': ['piilottaa', 'salata'], 'six': ['kuusi'], 'fir': ['kuusi']}

into this:

{'liikuttaa': ['move'], 'piilottaa': ['hide'], 'salata': ['hide'], 'kuusi': ['six', 'fir']}

Basically reversing this dictionary. Also the values of the new dictionary should be in list form like shown.

I have already tried using the zip function, reversing through (v,k) but everytime I get the same error: "unhashable type list".

def reverse_dictionary(d):    
    reverse=list(zip(d.values(),d.keys()))
    return reverse

Output should be this:

{'liikuttaa': ['move'], 'piilottaa': ['hide'], 'salata': ['hide'], 'kuusi': ['six', 'fir']}

You can use a defaultdict with a list :

from collections import defaultdict
from pprint import pprint

d = {'move': ['liikuttaa'],
     'hide': ['piilottaa', 'salata'],
     'six': ['kuusi'],
     'fir': ['kuusi']}

result = defaultdict(list)

for key, values in d.items():
    for value in values:
        result[value].append(key)

pprint(dict(result))

Output:

{'kuusi': ['fir', 'six'],
 'liikuttaa': ['move'],
 'piilottaa': ['hide'],
 'salata': ['hide']}

Or you can use a normal dict with setdefault :

result = {}

for key, values in d.items():
    for value in values:
        result.setdefault(value, []).append(key)

I would first create a generator that generators key, values pairs in the existing dictionary:

def pairs(d):
    for key in d:
        for value in d[key]:
            yield key, value

Then use defaultdict to create the reversed structure:

from collections import defaultdict
reversed_d = defaultdict(list)

for key, value in pairs(d):
    reversed_d[value].append(key)

A nested list comprehension will do this:

{vv: k for k, v in d.items() for vv in v}

Edit

I misunderstood your requirement. This is better:

from collections import defaultdict
new_dict = defaultdict(list)
for k, v in d.items()
    for val in v:
        new_dict[k].append(v)

This is not simple, dictionary reversing. You also need to access/create the inner list and populate it accordingly (while avoiding key clashing on the resulting dict).

One way of doing this is:

def reverse_dict_special(d):
    result = {}
    for k, vs in d.items():
        for v in vs:
            if v in result:
                result[v].append(k)
            else:
                result[v] = [k]
    return result

d = {'move': ['liikuttaa'], 'hide': ['piilottaa', 'salata'], 'six': ['kuusi'], 'fir': ['kuusi']}
reverse_dict_special(d)
# {'liikuttaa': ['move'],
#  'piilottaa': ['hide'],
#  'salata': ['hide'],
#  'kuusi': ['six', 'fir']}

Note that this does not require the use of collections.defaultdict or using dict.setdefault() as proposed by @PeterWood. Indeed the proposed method seems to get to faster results then both the other two:

from collections import defaultdict

def reverse_dict_special2(d):
    result = defaultdict(list)
    for key, values in d.items():
        for value in values:
            result[value].append(key)
    return result


def reverse_dict_special3(d):
    result = {}
    for key, values in d.items():
        for value in values:
            result.setdefault(value, []).append(key)
    return result


%timeit reverse_dict_special(d)
# 1.22 µs ± 29.8 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%timeit reverse_dict_special2(d)
# 2.04 µs ± 44 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit reverse_dict_special3(d)
# 1.55 µs ± 18.6 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

( EDITED : I had misunderstood the question at first, and did not realize that the input inner lists may have had multiple items)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM