sorted(list)
与list.sort()
的区别是什么?
list.sort
会就地修改列表并返回None
sorted
接受任何可迭代对象并返回一个已排序的新列表。
sorted
相当于这个Python实现,但CPython内置函数应该会运行得更快,因为它是用C编写的:
def sorted(iterable, key=None):
new_list = list(iterable)
new_list.sort(key=key)
return new_list
何时使用哪种方法?
- 当您不希望保留原始排序顺序(因此您将能够在内存中就地重用列表)且您是该列表的唯一所有者时,请使用
list.sort
(如果列表由其他代码共享并且您对其进行了更改,则可能会引入使用该列表的错误。)
- 当您想要保留原始排序顺序或者想要创建一个仅由本地代码拥有的新列表时,请使用
sorted
。
在 list.sort() 后是否可以检索到列表的原始位置?
不行-除非您自己复制了该信息,否则该信息将因原地排序而丢失。
"哪个更快?速度有多快?"
为了说明创建新列表的惩罚,使用timeit模块,这是我们的设置:
import timeit
setup = """
import random
lists = [list(range(10000)) for _ in range(1000)] # list of lists
for l in lists:
random.shuffle(l) # shuffle each list
shuffled_iter = iter(lists) # wrap as iterator so next() yields one at a time
"""
以下是我们对一个随机排列的10000个整数列表进行测试的结果,如您所见,我们已经证明了一个旧的列表创建费用谬论是错误的:
Python 2.7
>>> timeit.repeat("next(shuffled_iter).sort()", setup=setup, number = 1000)
[3.75168503401801, 3.7473005310166627, 3.753129180986434]
>>> timeit.repeat("sorted(next(shuffled_iter))", setup=setup, number = 1000)
[3.702025591977872, 3.709248117986135, 3.71071034099441]
Python 3
>>> timeit.repeat("next(shuffled_iter).sort()", setup=setup, number = 1000)
[2.797430992126465, 2.796825885772705, 2.7744789123535156]
>>> timeit.repeat("sorted(next(shuffled_iter))", setup=setup, number = 1000)
[2.675589084625244, 2.8019039630889893, 2.849375009536743]
经过一些反馈,我决定进行另一个测试,具有不同的特征。在这里,我为每次迭代提供了相同的长度为100,000的随机排序列表,共进行了1,000次。
import timeit
setup = """
import random
random.seed(0)
lst = list(range(100000))
random.shuffle(lst)
"""
我认为这种更大的排序方式的差异来自Martijn提到的复制,但它并没有像旧的、更流行的答案中所述那样占据主导地位,在这里,时间增加只有约10%。
>>> timeit.repeat("lst[:].sort()", setup=setup, number = 10000)
[572.919036605, 573.1384446719999, 568.5923951]
>>> timeit.repeat("sorted(lst[:])", setup=setup, number = 10000)
[647.0584738299999, 653.4040515829997, 657.9457361929999]
我还在更小的排序上运行了上述代码,并发现新的sorted
副本版本在长度为1000的排序中仍需要大约2%的更长运行时间。
Poke也运行了自己的代码,以下是代码:
setup = '''
import random
random.seed(12122353453462456)
lst = list(range({length}))
random.shuffle(lst)
lists = [lst[:] for _ in range({repeats})]
it = iter(lists)
'''
t1 = 'l = next(it); l.sort()'
t2 = 'l = next(it); sorted(l)'
length = 10 ** 7
repeats = 10 ** 2
print(length, repeats)
for t in t1, t2:
print(t)
print(timeit(t, setup=setup.format(length=length, repeats=repeats), number=repeats))
他进行了1000000长度排序(运行了100次),结果相似,但时间只增加了约5%,以下是输出结果:
10000000 100
l = next(it)
610.5015971539542
l = next(it)
646.7786222379655
结论:
使用 sorted
对大型列表进行排序并复制会占据主导地位,但是排序本身才是操作的主导因素,围绕这些差异组织代码将是过早的优化。当我需要一个新的已排序数据列表时,我会使用 sorted
,而当我需要原地排序列表时,我会使用 list.sort
,并让它决定我的用法。
sorted()
但认为它是一个列表,请注意,你会得到一个列表结果,而不是一个字符串。例如,sorted("abcd", reverse=True)
会得到['d', 'c', 'b', 'a']
而不是"dcba"
。 - smcilist.sort()
返回None
而不是新list
相关的问题都被归为了这里,但它们最好被归为更具体的问题为什么“return list.sort()”返回None而不是列表?。 - ShadowRanger