以下是解决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这样的函数调用比直接循环更快?
谢谢。
答案 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))))