sorted(list) 与 list.sort() 有什么区别?
-
list.sort 就地改变列表并返回 None
-
sorted 接受任何可迭代并返回一个新列表,已排序。
sorted 相当于这个 Python 实现,但 CPython 内置函数应该运行得更快,因为它是用 C 编写的:
def sorted(iterable, key=None):
new_list = list(iterable) # make a new list
new_list.sort(key=key) # sort it
return new_list # return it
什么时候用哪个?
- 如果您不希望保留原始排序顺序,请使用
list.sort
(因此,您将能够在内存中就地重用列表。)以及何时
您是列表的唯一所有者(如果列表由其他代码共享
如果你改变它,你可能会在使用该列表的地方引入错误。)
- 当您想要保留原始排序顺序或当您
希望创建一个只有您的本地代码拥有的新列表。
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 个整数列表的结果,正如我们在这里看到的,我们已经反驳了 an older list creation expense myth:
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]
经过一些反馈后,我决定需要另一个具有不同特征的测试。在这里,我为每次迭代 1,000 次提供相同的随机排序列表,长度为 100,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); l.sort()
610.5015971539542
l = next(it); sorted(l)
646.7786222379655
结论:
使用sorted 进行排序的大型列表复制可能会主导差异,但排序本身会主导操作,围绕这些差异组织代码将是过早的优化。当我需要一个新的数据排序列表时,我会使用sorted,当我需要对列表进行就地排序时,我会使用list.sort,并让它决定我的用法。