我有一个大的字典class UsersController < ApplicationController
def new
role, model = request.path.split("/")[1, 2] # ["", "admin", "user"]
@user = model.classify.constantize.new(role: role)
end
end
(最多1百万个项目),我想取N(典型值为N = 10K-20K)项,并将它们存储在新的字典src
中并将其余的项目仅保留在dst
中。拿走N个项目都没关系。我正在寻找在Python 3.6或3.7上实现此目标的最快方法。
到目前为止我发现的最快方法:
src
还有什么更好的吗?即使是微不足道的收益也不错。
答案 0 :(得分:19)
在dict
内部进行简单的理解即可:
dict(src.popitem() for _ in range(20000))
这里有timing tests
setup = """
src = {i: i ** 3 for i in range(1000000)}
def method_1(d):
dst = {}
while len(dst) < 20000:
item = d.popitem()
dst[item[0]] = item[1]
return dst
def method_2(d):
return dict(d.popitem() for _ in range(20000))
"""
import timeit
print("Method 1: ", timeit.timeit('method_1(src)', setup=setup, number=1))
print("Method 2: ", timeit.timeit('method_2(src)', setup=setup, number=1))
结果:
Method 1: 0.007701821999944514
Method 2: 0.004668198998842854
答案 1 :(得分:9)
这还快一点:
from itertools import islice
def method_4(d):
result = dict(islice(d.items(), 20000))
for k in result: del d[k]
return result
与其他版本相比,使用Netwave的测试用例:
Method 1: 0.004459443036466837 # original
Method 2: 0.0034434819826856256 # Netwave
Method 3: 0.002602717955596745 # chepner
Method 4: 0.001974945073015988 # this answer
额外的提速似乎来自避免C和Python函数之间的转换。从反汇编中,我们可以注意到dict
实例化发生在C端,只有3个来自Python的函数调用。循环使用DELETE_SUBSCR
操作码而不需要函数调用:
>>> dis.dis(method_4)
2 0 LOAD_GLOBAL 0 (dict)
2 LOAD_GLOBAL 1 (islice)
4 LOAD_FAST 0 (d)
6 LOAD_ATTR 2 (items)
8 CALL_FUNCTION 0
10 LOAD_CONST 1 (20000)
12 CALL_FUNCTION 2
14 CALL_FUNCTION 1
16 STORE_FAST 1 (result)
3 18 SETUP_LOOP 18 (to 38)
20 LOAD_FAST 1 (result)
22 GET_ITER
>> 24 FOR_ITER 10 (to 36)
26 STORE_FAST 2 (k)
28 LOAD_FAST 0 (d)
30 LOAD_FAST 2 (k)
32 DELETE_SUBSCR
34 JUMP_ABSOLUTE 24
>> 36 POP_BLOCK
4 >> 38 LOAD_FAST 1 (result)
40 RETURN_VALUE
与method_2
中的迭代器相比:
>>> dis.dis(d.popitem() for _ in range(20000))
1 0 LOAD_FAST 0 (.0)
>> 2 FOR_ITER 14 (to 18)
4 STORE_FAST 1 (_)
6 LOAD_GLOBAL 0 (d)
8 LOAD_ATTR 1 (popitem)
10 CALL_FUNCTION 0
12 YIELD_VALUE
14 POP_TOP
16 JUMP_ABSOLUTE 2
>> 18 LOAD_CONST 0 (None)
20 RETURN_VALUE
每个项目都需要一个Python到C函数的调用。
答案 2 :(得分:3)
我发现使用字典理解可以更快地(-10%的速度)使用range
来产生并解压缩键和值的循环
dst = {key:value for key,value in (src.popitem() for _ in range(20000))}
在我的机器上:
your code: 0.00899505615234375
my code: 0.007996797561645508
大约快了12%,还不错,但不如Netwave simpler answer那样开箱
如果您要在流程中转换键或值,则此方法很有用。