星图比嵌套列表理解要快吗?

时间:2018-11-19 17:51:17

标签: python performance itertools

以下是解决here中任务的代码:

def maximizingXor(l, r):
    return max([i^j for i in range(l, r+1) for j in range(i, r+1)])

这是我的丑陋解决方案:

from itertools import combinations, starmap
from operator import xor

# Complete the maximizingXor function below.
def maximizingXor(l, r):
    return max(starmap(xor, combinations(range(l,r+1),2)))

它不像那样美丽,但是在l = 10,r = 15时确实更快:
对于我的解决方案,%timeit显示为3.81 µs±156 ns,对于没有功能调用的解决方案,每个循环为8.67 µs±1.1 µs。
所以这是一个问题-为什么要更快? 更一般地说: 在什么情况下,像itertools这样的函数调用比直接循环更快? 谢谢。

2 个答案:

答案 0 :(得分:0)

第一个音符max与任何可迭代项一起使用。这可以是列表生成器。哪种效率更高取决于输入的大小和硬件限制。列表会占用大量内存,但是生成器表达式在next调用中的开销更大。

以下时序是针对同一逻辑的4个变体进行2次不同的运行。如您所见,对于非常大的l, r来说,生成器表达式比列表理解更有效,对于较小的l, r则相反。

starmap也是懒惰的,但避免了生成器表达式,因此比两者效率更高。用通俗易懂的术语讲,starmap具有懒惰的优势,它们使用优化的C代码进行迭代。

# run 1 inputs
l, r = 10000, 15000

# run 2 inputs
l, r = 1000, 1500

%timeit maximizingXor_lc(l, r)   # 2.83 s per loop, 18.2 ms per loop
%timeit maximizingXor_ge(l, r)   # 2.48 s per loop, 21.5 ms per loop
%timeit maximizingXor(l, r)      # 1.53 s per loop, 15.2 ms per loop
%timeit maximizingXor_zip(l, r)  # 6.52 s per loop, 51.7 ms per loop

基准代码

from itertools import combinations, starmap
from operator import xor

def maximizingXor_lc(l, r):
    return max([i^j for i in range(l, r+1) for j in range(i, r+1)])

def maximizingXor_ge(l, r):
    return max(i^j for i in range(l, r+1) for j in range(i, r+1))

def maximizingXor(l, r):
    return max(starmap(xor, combinations(range(l,r+1), 2)))

def maximizingXor_zip(l, r):
    return max(map(xor, *zip(*combinations(range(l,r+1), 2))))

assert maximizingXor_lc(l, r) == maximizingXor(l, r)
assert maximizingXor_lc(l, r) == maximizingXor_ge(l, r)
assert maximizingXor_lc(l, r) == maximizingXor_zip(l, r)

答案 1 :(得分:0)

以前,我用不正确的代码发布了此信息。查找列表的最大值比生成器的最大值更快。如果范围足够小以适合内存,那么创建列表并查找最大值的结果会更快。

def maximizingXor_lst(l, r):
    return max(list(starmap(xor, combinations(range(l, r+1), 2))))