2
votes

Set-up

I have a large dictionary with unique keys, unique values and non-unique values in lists.

Dictionary looks like,

d = {'a': ['1','2','3'],'b': ['1'],'c': ['1','3']}

Problem

I'd like to swap the keys and values such that,

d_inverse = {'1': ['a', 'b', 'c'], '2': ['a'],'3': ['a', 'c']}

I've found the following answers about swapping keys and values,

and about swapping keys with values in lists,

the last answer comes close, but doesn't manage non-unique values in lists.

That is,

{k: oldk for oldk, oldv in d.items() for k in oldv}

produces

{'1': 'c', '2': 'a', '3': 'c'}

How do I account for the non-unique values and don't lose information?

4
Consider using a loop?user202729
Note you have both int and string values in the lists in d, so your output isn't quite right (it should have both '1' and 1 keys).match
Thanks, I edited my example.LucSpan

4 Answers

4
votes

One way is using collections.defaultdict:

d = {'a': ['1','2','3'],'b': ['1'],'c': ['1','3']}

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

dict(d_dict)
#{'1': ['a', 'b', 'c'], '2': ['a'], '3': ['a', 'c']}
1
votes

Using a for-loop

d = {'a': ['1','2','3'],'b': [1],'c': ['1','3']}
res = {}

for k,v in d.items():           #Iterate dictionary.
    for i in v:                 #Iterate List
        i = str(i)              #Convert element to string
        if i not in res:        #Check if key in dictionary.
            res[i] = [k]
        else:
            res[i].append(k)    #Else append element. 
print(res)

Output:

{'1': ['a', 'c', 'b'], '3': ['a', 'c'], '2': ['a']}
1
votes

Someone answered this question here

inv_map = {}
for k, v in my_map.iteritems():
    inv_map.setdefault(v, []).append(k)

with a small change it works as we want:

d = {'a': ['1','2','3'],'b': ['1'],'c': ['1','3']}

inv_map = {}
for k, vs in d.items():
    for v in vs:
        inv_map.setdefault(v, []).append(k)


print(inv_map)
>>> {'1': ['a', 'b', 'c'], '2': ['a'], '3': ['a', 'c']}
1
votes

You can also use a dictionary comprehension:

from string import ascii_lowercase as alphabet
d = {'a': ['1','2','3'],'b': ['1'],'c': ['1','3']}
new_d = {str(alphabet.index(a)+1):[alphabet[int(i)-1] for i in b] for a, b in d.items()}

Output:

{'1': ['a', 'b', 'c'], '2': ['a'], '3': ['a', 'c']}