Python Forum
5 variants to invert dictionaries with non-unique values - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: 5 variants to invert dictionaries with non-unique values (/thread-29386.html)



5 variants to invert dictionaries with non-unique values - Drakax1 - Aug-31-2020

Hi all,

I was wondering if it was possible to rewrite the variants #1 #2 or #3 into a single line of code like variants #4 and #5?

my_map = {'a': 3, 'c': 2, 'b': 2, 'e': 3, 'd': 1, 'f': 2}

#output = {3: ['a', 'e'], 2: ['c', 'b', 'f'], 1: ['d']}

#var1
inv_map = {}
for k, v in my_map.items():
  inv_map[v] = inv_map.get(v, []) + [k]
print(inv_map)

#var2 (The best/fastest overall?)
inv_map2 = {}
for k, v in my_map.items():
  inv_map2.setdefault(v, set()).add(k)
print(inv_map2)

#var3
inv_map3 = {}
for k, v in my_map.items():
  inv_map3.setdefault(v, list()).append(k)
print(inv_map3)

#var4
print({v:[k for k in my_map.keys() if my_map[k] == v ] for k,v in my_map.items()})

#var5
print({v:[k for k in my_map if my_map[k] == v] for v in my_map.values()})



RE: 5 variants to invert dictionaries with non-unique values - DeaD_EyE - Aug-31-2020

Not a one-liner, but a code snippet, which is readable:

from collections import defaultdict


result = defaultdict(list)
for key, value in my_map.items():
    result[value].append(key)



RE: 5 variants to invert dictionaries with non-unique values - snippsat - Aug-31-2020

(Aug-31-2020, 09:20 AM)Drakax1 Wrote: I was wondering if it was possible to rewrite the variants #1 #2 or #3 into a single
Possible,but not gone try it Wink
If have to think long about then then the readability in that line will be poor.
I would probably write this like @DeaD_EyE,as i like defaultdict and in general stuff from collections module.

Drakax1 Wrote:#var2 (The best/fastest overall?)
That's and interpretation as best also be looked at as most pythonic/readable.
Here a setup with timeit,if want to test speed.
import timeit

ver_1 = '''\
my_map = {'a': 3, 'c': 2, 'b': 2, 'e': 3, 'd': 1, 'f': 2}
inv_map = {}
for k, v in my_map.items():
  inv_map[v] = inv_map.get(v, []) + [k]'''

ver_2 = '''\
my_map = {'a': 3, 'c': 2, 'b': 2, 'e': 3, 'd': 1, 'f': 2}
inv_map2 = {}
for k, v in my_map.items():
  inv_map2.setdefault(v, set()).add(k)'''


ver_3 = '''\
from collections import defaultdict

my_map = {'a': 3, 'c': 2, 'b': 2, 'e': 3, 'd': 1, 'f': 2}
result = defaultdict(list)
for key, value in my_map.items():
    result[value].append(key)'''

ver_4_5 = '''\
my_map = {'a': 3, 'c': 2, 'b': 2, 'e': 3, 'd': 1, 'f': 2}

#{v:[k for k in my_map.keys() if my_map[k] == v ] for k,v in my_map.items()}
{v:[k for k in my_map if my_map[k] == v] for v in my_map.values()}'''

print(timeit.Timer(stmt=ver_2).timeit(number=10000000))
So ver_1 and 2 is fast.
So can get this this 10000000 run with average time down to 5-sec,but then i run PyPy Shocked
Here run ver_1.
# Python 3.8
G:\pypy3.6-v7.1.1
λ python test_map.py
19.0559965

# PyPy 3.6 ver 7.1
G:\pypy3.6-v7.1.1
λ pypy3 test_map.py
5.330786000000001