Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/288.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Python中对列表排序时传递reverse=True是否会影响效率?_Python_Performance_Sorting_Reverse_Time Complexity - Fatal编程技术网

在Python中对列表排序时传递reverse=True是否会影响效率?

在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()相当 当然,基准测试是

在Python中对列表调用
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 to
list.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)