Skip to content
Advertisement

is there a faster way to get multiple keys from dictionary?

I have a dictionary:

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

Then I have a list of keys:

l = ['a', 'b', 'z']

My desired result is:

[1, 2, None]

What I’m doing so far is:

[d.get(k) for k in l]

Is there a faster way? Perhaps without for?

Advertisement

Answer

You could use:

>>> list(map(d.get, l))
[1, 2, None]

It has two advantages:

  • It performs the d.get lookup only once – not each iteration
  • Only CPython: Because dict.get is implemented in C and map is implemented in C it can avoid the Python layer in the function call (roughly speaking the details are a bit more complicated).

As for timings (performed on Python 3.6 in a Jupyter notebook):

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

%timeit list(map(d.get, l))
594 ns ± 41.7 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

%timeit [d.get(k) for k in l]
508 ns ± 17.1 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

Note that this is actually slower in this case! That’s because for short iterables the map and list overhead dominate. So if you want it faster on short iterables stick with your approach.

With longer l you see that list(map(...)) eventually becomes faster:

d = {'a':1, 'b':2, 'c':3, 'd':4}
l = [random.choice(string.ascii_lowercase) for _ in range(10000)]

%timeit list(map(d.get, l))
663 µs ± 64.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit [d.get(k) for k in l]
1.13 ms ± 7.55 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

However that’s still “just” a factor of 2 faster.

User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement