2

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?

LucSpan
  • 1,831
  • 6
  • 31
  • 66

4 Answers4

4

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']}
Aran-Fey
  • 39,665
  • 11
  • 104
  • 149
Transhuman
  • 3,527
  • 1
  • 9
  • 15
1

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']}
Rakesh
  • 81,458
  • 17
  • 76
  • 113
1

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']}
Maarten-vd-Sande
  • 3,413
  • 10
  • 27
1

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']}
Ajax1234
  • 69,937
  • 8
  • 61
  • 102