Python dictionary: Get list of values for list of keys
A list comprehension seems to be a good way to do this:
>>> [mydict[x] for x in mykeys][3, 1]
A couple of other ways than list-comp:
- Build list and throw exception if key not found:
map(mydict.__getitem__, mykeys)
- Build list with
None
if key not found:map(mydict.get, mykeys)
Alternatively, using operator.itemgetter
can return a tuple:
from operator import itemgettermyvalues = itemgetter(*mykeys)(mydict)# use `list(...)` if list is required
Note: in Python3, map
returns an iterator rather than a list. Use list(map(...))
for a list.
A little speed comparison:
Python 2.7.11 |Anaconda 2.4.1 (64-bit)| (default, Dec 7 2015, 14:10:42) [MSC v.1500 64 bit (AMD64)] on win32In[1]: l = [0,1,2,3,2,3,1,2,0]In[2]: m = {0:10, 1:11, 2:12, 3:13}In[3]: %timeit [m[_] for _ in l] # list comprehension1000000 loops, best of 3: 762 ns per loopIn[4]: %timeit map(lambda _: m[_], l) # using 'map'1000000 loops, best of 3: 1.66 µs per loopIn[5]: %timeit list(m[_] for _ in l) # a generator expression passed to a list constructor.1000000 loops, best of 3: 1.65 µs per loopIn[6]: %timeit map(m.__getitem__, l)The slowest run took 4.01 times longer than the fastest. This could mean that an intermediate result is being cached 1000000 loops, best of 3: 853 ns per loopIn[7]: %timeit map(m.get, l)1000000 loops, best of 3: 908 ns per loopIn[33]: from operator import itemgetterIn[34]: %timeit list(itemgetter(*l)(m))The slowest run took 9.26 times longer than the fastest. This could mean that an intermediate result is being cached 1000000 loops, best of 3: 739 ns per loop
So list comprehension and itemgetter are the fastest ways to do this.
UPDATE:For large random lists and maps I had a bit different results:
Python 2.7.11 |Anaconda 2.4.1 (64-bit)| (default, Dec 7 2015, 14:10:42) [MSC v.1500 64 bit (AMD64)] on win32In[2]: import numpy.random as nprndl = nprnd.randint(1000, size=10000)m = dict([(_, nprnd.rand()) for _ in range(1000)])from operator import itemgetterimport operatorf = operator.itemgetter(*l)%timeit f(m)%timeit list(itemgetter(*l)(m))%timeit [m[_] for _ in l] # list comprehension%timeit map(m.__getitem__, l)%timeit list(m[_] for _ in l) # a generator expression passed to a list constructor.%timeit map(m.get, l)%timeit map(lambda _: m[_], l)1000 loops, best of 3: 1.14 ms per loop1000 loops, best of 3: 1.68 ms per loop100 loops, best of 3: 2 ms per loop100 loops, best of 3: 2.05 ms per loop100 loops, best of 3: 2.19 ms per loop100 loops, best of 3: 2.53 ms per loop100 loops, best of 3: 2.9 ms per loop
So in this case the clear winner is f = operator.itemgetter(*l); f(m)
, and clear outsider: map(lambda _: m[_], l)
.
UPDATE for Python 3.6.4:
import numpy.random as nprndl = nprnd.randint(1000, size=10000)m = dict([(_, nprnd.rand()) for _ in range(1000)])from operator import itemgetterimport operatorf = operator.itemgetter(*l)%timeit f(m)%timeit list(itemgetter(*l)(m))%timeit [m[_] for _ in l] # list comprehension%timeit list(map(m.__getitem__, l))%timeit list(m[_] for _ in l) # a generator expression passed to a list constructor.%timeit list(map(m.get, l))%timeit list(map(lambda _: m[_], l)1.66 ms ± 74.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)2.1 ms ± 93.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)2.58 ms ± 88.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)2.36 ms ± 60.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)2.98 ms ± 142 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)2.7 ms ± 284 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)3.14 ms ± 62.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
So, results for Python 3.6.4 is almost the same.