`sorted(list)`和`list.sort()`有什么区别?

295 投票
7 回答
153618 浏览
提问于 2025-04-17 22:34

list.sort() 是用来对列表进行排序的,它会直接修改原来的列表。而 sorted(list) 则是返回一个新的排序后的列表,原来的列表不会被改变。

  • 在什么情况下我们更喜欢用其中一个呢?
  • 哪个方法更高效?差别有多大?
  • 在使用 list.sort() 之后,列表能否恢复到未排序的状态?

请参考 为什么这些列表操作(方法)返回 None,而不是结果列表? 来解决那些因为不小心把 .sort() 的结果赋值给变量,而不是使用 sorted 或者单独的语句的提问。正确的调试会显示 .sort() 返回了 None,这时“为什么?”就是剩下的问题了。

7 个回答

5

注意:sort()和sorted()之间最简单的区别是:sort()不返回任何值,而sorted()会返回一个可迭代的列表。

sort()不返回任何值。

sort()这个方法只是把给定列表里的元素按照特定的顺序(升序或降序)进行排序,但它不会返回任何值。

sort()方法的语法是:

list.sort(key=..., reverse=...)

另外,你也可以使用Python内置的函数sorted()来达到同样的目的。sorted函数会返回一个已排序的列表。

 list=sorted(list, key=..., reverse=...)
5

这里有几个简单的例子来展示它们之间的区别:

看看这里的数字列表:

nums = [1, 9, -3, 4, 8, 5, 7, 14]

当我们对这个列表使用 sorted 时,sorted 会创建一个列表的副本。(这意味着你原来的列表不会改变。)

让我们来看看。

sorted(nums)

返回的结果是

[-3, 1, 4, 5, 7, 8, 9, 14]

再看看 nums 列表

nums

我们看到原来的列表(没有改变,也没有排序)。sorted 并没有改变原来的列表。

[1, 2, -3, 4, 8, 5, 7, 14]

如果我们对同样的 nums 列表使用 sort 函数,它会直接改变这个列表。

让我们来看看。

首先检查我们的 nums 列表,确保内容还是一样的。

nums

[-3, 1, 4, 5, 7, 8, 9, 14]

nums.sort()

现在原来的 nums 列表已经改变,查看 nums 时,我们看到原来的列表已经改变,并且现在是排序过的。

nums
[-3, 1, 2, 4, 5, 7, 8, 14]
16

主要的区别在于,sorted(some_list) 会返回一个新的 list

a = [3, 2, 1]
print sorted(a) # new list
print a         # is not modified

some_list.sort()在原地对列表进行排序

a = [3, 2, 1]
print a.sort() # in place
print a         # it's modified

需要注意的是,由于 a.sort() 不会返回任何东西,所以 print a.sort() 会输出 None


使用 list.sort() 后,能否恢复列表的原始位置?

不能,因为它会修改原始列表。

67

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(这样你可以在内存中直接重用这个列表),并且当你是这个列表的唯一拥有者时(如果这个列表被其他代码共享,而你又修改了它,可能会在其他地方引入错误)。
  • 当你想保留原来的排序顺序,或者想创建一个只属于你本地代码的新列表时,使用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个元素的列表,每次迭代1000次。

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,这将决定我的使用方式。

435

sorted() 会返回一个全新的排序列表,而不会改变原来的列表。list.sort() 则是在原地排序,也就是说它会直接修改原来的列表,并且返回 None(就像所有在原地进行的操作一样)。

sorted() 可以用于任何可迭代的对象,不仅仅是列表。比如字符串、元组、字典(你会得到字典的键)、生成器等等,它都会返回一个包含所有元素的排序列表。

  • 当你想要改变原来的列表时,使用 list.sort();当你想要一个新的排序对象时,使用 sorted()。如果你想排序的东西还不是列表,但可以迭代,记得用 sorted()

  • 对于列表来说,list.sort()sorted() 快,因为它不需要创建一个副本。对于其他可迭代对象,你就只能用 sorted() 了。

  • 不,你不能找回原来的位置。一旦你调用了 list.sort(),原来的顺序就没了。

撰写回答