在Python中对列表排序时传递reverse=True是否会影响效率?
在Python中对列表调用在Python中对列表排序时传递reverse=True是否会影响效率?,python,performance,sorting,reverse,time-complexity,Python,Performance,Sorting,Reverse,Time Complexity,在Python中对列表调用sort()时,传递cmp=f会减慢排序速度。传递reverse=True是否会以任何方式影响排序的效率(或者它与不反转的排序相同)?该sort()方法是本机方法,即它是用宿主语言而不是Python实现的。在cmp参数中传递函数将强制本机实现调用该函数并在每次迭代中执行Python代码。这就是表演热的来源 另一方面,在reverse参数中传递True,只会指示本机算法对项进行反向排序。如果未设置cmp,则只涉及本机代码,因此性能应与普通sort()相当 当然,基准测试是
sort()
时,传递cmp=f
会减慢排序速度。传递reverse=True
是否会以任何方式影响排序的效率(或者它与不反转的排序相同)?该sort()
方法是本机方法,即它是用宿主语言而不是Python实现的。在cmp
参数中传递函数将强制本机实现调用该函数并在每次迭代中执行Python代码。这就是表演热的来源
另一方面,在reverse
参数中传递True
,只会指示本机算法对项进行反向排序。如果未设置cmp
,则只涉及本机代码,因此性能应与普通sort()
相当
当然,基准测试是肯定的。我想不会因为
reverse=True
而减速,因为结果可以简单地通过一路上的反向决策来构建。当基准测试正确时(多亏了邓肯),这一猜测得到了证实:
In [18]: import random
In [57]: x = range(1000)
In [58]: random.shuffle(x)
In [59]: %timeit sorted(x)
1000 loops, best of 3: 341 us per loop
In [54]: x = range(1000)
In [55]: random.shuffle(x)
In [56]: %timeit sorted(x, reverse = True)
1000 loops, best of 3: 344 us per loop
我用不同大小的列表重复了几次这个测试(
N=10**3,10**4,10**5
),得到了一致的结果。从我的基准测试来看,似乎有一点不同:
import timeit
setup = """
import random
random.seed(1)
l = range(10000)
random.shuffle(l)
"""
run1 = """
sorted(l)
"""
run2 = """
sorted(l, reverse=True)
"""
n1 = timeit.timeit(run1, setup, number=10000)
n2 = timeit.timeit(run2, setup, number=10000)
print n1, n2
print (n2/n1 - 1)*100,"%"
结果(在我的机器上):
相同的运行,但对于1000个元素的列表:
2.80148005486 2.74061703682
-2.17253083528 %
# ...another round...
2.90553498268 2.86594104767
-1.36270722083 %
令人惊讶的是,对列表进行反向排序需要更长的时间。其他答案已经用很好的基准说明了这一点。我查看了来源,发现: 因此,为了获得排序后的输出,列表在排序前被反转,然后被排序,最后再次反转。撤销列表是一项O(n)操作,因此列表越长,您为此付出的代价就越高 这表明,如果您正在构建自定义键函数,那么您可以通过直接否定它来为大列表节省时间:
very_long_list.sort(key=lambda x, y: -cmp(x, y))
而不是使用reversed=True
:
very_long_list.sort(key=lambda x, y: cmp(x, y), reverse=True)
在这种情况下,您当然可以在第二种情况下直接传递
key=cmp
,从而通过lambda函数保存额外的调用。但是如果您有一个更大的表达式,那么这可能会有回报。请注意,cmp
arg tolist.sort
和sorted
内置函数在Python2.x中被弃用,在3.x中不再允许,因为它们的性能很差,正如您所注意到的。相反,您应该使用键
arg来定义自定义排序顺序。+0.75表示有趣和有用的问题,+0.25表示正确使用“影响”一词。我认为您的基准被打破了。您应该尝试计时sorted(x)
,否则它会对已排序列表进行一次排序,然后是排序或反向排序所需时间的倍数。当我使用sorted(x)
尝试一个基准测试时,我得到了每个循环4.41mS,与x的249uS/262uS相反,没有差别。sort()
每次对相同的列表进行排序并不能证明有差别,因为排序时间将取决于数据分布。请注意,如果简单地否定比较函数,则反向排序将不再稳定。这就是为什么Python会进行反向/排序/反向洗牌来保持稳定性。+1用于代码探索。我还在下载焦油球…;-)@邓肯:你确定吗?我不认为这是真的:根据定义,sort(key=f)
对于任何f
都是稳定的,包括f
是一个否定比较函数的情况。看起来cpython代码做了双重反转,这样就不必因为性能原因而否定比较函数的结果,但是它可以这样做并且是正确的。不正确的做法是按普通键进行稳定排序,然后反转(排序前不反转)。@sdcvvc不,我不确定。真的,在所有2.x中都不赞成吗?我有一本2.3天和2.4天的书,书中有解释和鼓励。
very_long_list.sort(key=lambda x, y: -cmp(x, y))
very_long_list.sort(key=lambda x, y: cmp(x, y), reverse=True)