是否有更快的方法从字典中获取多个键?

Eze*_*r K 6 python performance dictionary key-value

我有一本字典:

d = {'a':1, 'b':2, 'c':3, 'd':4}
Run Code Online (Sandbox Code Playgroud)

然后我有一个键列表:

l = ['a', 'b', 'z']
Run Code Online (Sandbox Code Playgroud)

我想要的结果是:

[1, 2, None]
Run Code Online (Sandbox Code Playgroud)

到目前为止我所做的是:

[d.get(k) for k in l]
Run Code Online (Sandbox Code Playgroud)

有更快的方法吗?也许没有for

MSe*_*ert 13

你可以使用:

>>> list(map(d.get, l))
[1, 2, None]
Run Code Online (Sandbox Code Playgroud)

它有两个优点:

  • 它只执行d.get一次查找 - 而不是每次迭代
  • 只有CPython:因为dict.get用C实现并且用C map实现它可以避免函数调用中的Python层(粗略地说细节有点复杂).

至于时间(在Jupyter笔记本中的Python 3.6上执行):

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)
Run Code Online (Sandbox Code Playgroud)

请注意,在这种情况下,这实际上更慢!那是因为对于短迭代而言map,list开销占主导地位.因此,如果您希望在短迭代中更快地坚持您的方法.

随着时间的推移l你会看到list(map(...))最终变得更快:

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)
Run Code Online (Sandbox Code Playgroud)

然而,这仍然"只是"快2倍.


Dee*_*ace 5

重要的是要注意这里的瓶颈不是字典的大小,而是键列表的大小(当然还有方法查找时间,散列被查找的键所需的时间等)

考虑以下:

from timeit import Timer

d = {1: 'a'}
keys = [1 for _ in range(1000)]

def _map():
    return list(map(d.get, keys))

def _map_single_lookup():
    g = d.get
    return list(map(g, keys))

def _list_comp():
    return [d.get(key) for key in keys]

def _list_comp_single_lookup():
    g = d.get
    return [g(key) for key in keys]

print(min(Timer(_map).repeat(100, 100)))
print(min(Timer(_map_single_lookup).repeat(100, 100)))
print(min(Timer(_list_comp).repeat(100, 100)))
print(min(Timer(_list_comp_single_lookup).repeat(100, 100)))

#  0.009307396466818774
#  0.009261678214412816
#  0.018456645101335933
#  0.011634828724497837
Run Code Online (Sandbox Code Playgroud)

  • 你的`_map`和`_map_single_lookup`完全等价.它们都只需要一次查询`d.get`. (4认同)