Reputation: 75
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']}
Upvotes: 1
Views: 116
Reputation: 24133
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)
Upvotes: 5
Reputation: 26896
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)
Upvotes: 0
Reputation: 599630
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)
Upvotes: 0
Reputation: 31260
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)
Upvotes: 2