python的sorted()函数是否保证稳定?


95

文档不能保证。还有其他记录在案的地方吗?

我猜想它可能是稳定的,因为可以保证列表上的sort方法是稳定的(注9:“从Python 2.3开始,保证sort()方法是稳定的”),并且sorted在功能上相似。但是,我找不到任何明确的说法。

目的:如果两个记录中的主键相等,则需要基于主键和辅助键进行排序。如果保证sorted()是稳定的,那么我可以对辅助键进行排序,然后对主键进行排序,并获得所需的结果。

PS:为避免任何混乱,我使用“稳定”的含义是“排序是稳定的,如果它保证不更改比较相等的元素的相对顺序”。

Answers:


126

是的,该手册的目的实际上是为了确保它sorted的稳定性,并且确实使用与该sort方法完全相同的算法。我的确意识到文档不是100%清楚这种身份。总是很高兴地接受doc补丁!


2
我发现,如果我要对元组或列表进行排序,则只要“主”排序键相等,它最终都将通过“第二”键进行排序。例如,sorted([(1, 2), (1, 1)])返回[(1, 1), (1, 2)]而不是按相同的顺序/顺序返回原始输入。保证稳定性不应该意味着它应该返回原始[(1, 2), (1, 1)]输入吗?在这种情况下,你必须是明确的,并说sorted([(1, 2), (1, 1)], key=lambda t: t[0])
code_dredd

10
这不是这种情况下的预期结果吗?Python默认情况下将比较所有元素中的元组,而不仅仅是第一个“主要”元素。如果只想对第一个元素进行排序,则可以key显式传递参数。
Matias Grioni '17

2
@code_dredd,这是预期的行为。稳定排序的要点是使用“排序键”进行排序,但是具有相同排序键的两个不同元素的顺序相同。元组的默认排序键是该元组的所有元素。
Guyarad

27

他们是稳定的

顺便说一句:您有时可以通过将多遍排序组合到单遍排序中而忽略了解排序和排序是否稳定。

例如,如果要排序基于它们的对象last_namefirst_name属性,你可以做一个合格:

sorted_list= sorted(
    your_sequence_of_items,
    key= lambda item: (item.last_name, item.first_name))

利用元组比较。

此答案按原样涵盖了原始问题。对于与排序有关的其他问题,有Python排序方法


4
如果要反转排序,可能会产生不希望有的效果。例如,在对产品进行排序时,您可能希望首先对评级(升序)进行排序,然后对价格(也进行升序)进行排序。如果您将其反转,则希望按降序对评级进行排序,而按升序对价格进行排序。此解决方案不适用于此解决方案。
雷姆科·温特

2
@RemcoWendt:对您的描述没有要求。无论如何,请考虑key= lambda item: (-item.rating, item.price)或提供a cmp而不是key参数。不过,我仍然不确定您发表评论的目的。
tzot 2012年

1
确实不是必须的,但是当其他人阅读此书并在您的解决方案或使用Python的稳定排序功能之间做出选择时,想指出这一细微的区别。
雷姆科·温特

我懂了。换句话说,按对排序更清晰,因此是可取的,除非您关心性能。我以为两个稳定的排序比一对一排序要快一些,尽管差异可能可以忽略不计-?
osa

8
我想提一下@tzot,始终有这样的要求才能进行稳定的排序。例如,我有一个元组列表(费率,注释),注释按创建时的顺序保存,我想按费率排序并保持时间顺序,但是,我没有保存列表中的时间戳。简而言之,我只想按速率对列表进行排序,并保持注释的顺序相同。
wsysuper

3

同时更改了文档(相关的commit),并且的当前文档sorted明确保证:

内置sorted()功能保证稳定。如果可以保证不更改比较相等的元素的相对顺序,则排序是稳定的-这有助于多次通过排序(例如,按部门排序,然后按薪级等级排序)。

该文档的这一部分已添加到Python 2.7和Python 3.4(+)中,因此该语言版本的任何兼容实现都应具有稳定的sorted

请注意,对于CPython,list.sortPython 2.3起一直保持稳定

  • 蒂姆·彼得斯(Tim Peters)重新编写了他的list.sort()实现-这是一种“稳定的排序”(相等的输入在输出中以相同的顺序出现)并且比以前更快。

我目前尚不确定100%的sorted使用率list.sort,但现在还可以查看历史记录。但是很可能“总是”使用了它list.sort


0

Python 2.4“新增功能”文档有效地指出了sorted()首先创建一个列表,然后在其上调用sort()的事实,这为您提供了所需的保证,尽管不在“官方”文档中。如果您真的很担心,也可以只检查源。


1
您能指出它的意思吗?它说sorted()“就像就地list.sort()一样工作,并且“对新形成的副本进行排序”,但是我看不到它在内部使用sort()。
sundar-恢复莫妮卡

形成的“副本”是一个列表(这是作为返回值获得的列表),并且在返回之前在该列表上调用.sort()。QED。不,这不是一个无懈可击的证明,但在Python有了正式标准之前,您将无法获得证明。
彼得·汉森

0

现在,有关排序的Python 3.6文档指出:

排序保证稳定

此外,在该文档中,有一个指向稳定的Timsort的链接,其中指出:

自2.3版以来,Timsort一直是Python的标准排序算法

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.