【问题标题】:Is python's sorted() function guaranteed to be stable?python的sorted()函数能保证稳定吗?
【发布时间】:2009-12-16 15:30:01
【问题描述】:

documentation 不保证这一点。还有其他地方记录吗?

我猜它可能是稳定的,因为列表上的 sort 方法是 guaranteed to be stable(注意第 9 点:“从 Python 2.3 开始,sort() 方法保证是稳定的”),并且 sorted 在功能上相似.但是,我无法找到任何明确的来源。

目的:如果主键在两条记录中相等,我需要根据主键和辅助键进行排序。如果 sorted() 保证稳定,我可以先按次键排序,再按主键排序,得到我需要的结果。

PS:为避免任何混淆,我使用 stable 的意思是“如果保证不改变比较相等的元素的相对顺序,则该排序是稳定的”。

【问题讨论】:

    标签: python sorted stable-sort


    【解决方案1】:

    是的,手册的目的确实是保证sorted 是稳定的,并且确实使用与sort 方法完全相同的算法。我确实意识到文档对这个身份并不是 100% 清楚的。 doc 补丁总是被欣然接受!

    【讨论】:

    • 我发现,如果我对元组或列表进行排序,只要“主”排序键相等,它就会按“次”键排序。例如,sorted([(1, 2), (1, 1)]) 返回 [(1, 1), (1, 2)] 而不是以相同的顺序/顺序返回原始输入。稳定性的保证不应该意味着它应该返回原始的[(1, 2), (1, 1)] 输入吗?在这种情况下,你必须明确地说sorted([(1, 2), (1, 1)], key=lambda t: t[0])
    • 这不是在这种情况下所期望的吗?默认情况下,Python 将通过所有元素比较元组,而不仅仅是第一个“主要”元素。如果只想对第一个元素进行排序,可以显式传递key 参数。
    • @code_dredd 这是预期的行为。稳定排序的要点是使用“排序键”进行排序,但是具有相同排序键的两个不同元素将处于相同的顺序。元组的默认排序键是元组的所有元素。
    【解决方案2】:

    他们是stable。

    顺便说一句:通过将多遍排序合并到单遍排序中,您有时可以忽略知道 sort 和 sorted 是否稳定。

    例如,如果要根据对象的last_name、first_name 属性对对象进行排序,则可以一次性完成:

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

    利用元组比较。

    这个答案按原样涵盖了原始问题。更多与排序相关的问题,请联系Python Sorting How-To。

    【讨论】:

    • 如果您想反转排序,这可能会产生不良影响。例如,在对产品进行排序时,您可能希望首先按评级(升序)排序,然后按价格(也按升序)排序。如果你反转这个,你想按降序对评级进行排序,但按升序对价格进行排序。这不适用于此解决方案。
    • @RemcoWendt:您所描述的内容没有要求。在任何情况下,请考虑key= lambda item: (-item.rating, item.price) 或提供cmp 而不是key 参数。不过,我仍然不确定您发表评论的目的。
    • 确实不是必需的,但是当其他人阅读本文并在您的解决方案或使用 Python 的稳定排序功能之间做出选择时,想指出这种细微差别。
    • 我明白了。换句话说,成对排序更清晰,因此更可取,除非您关心性能。我想两种稳定的排序比一对排序要快一些,尽管差异可能可以忽略不计 - ?
    • @tzot 我想提一下,稳定排序总是有这样的要求。例如,我有一个元组列表 (rate, comment),cmet 是按照它们制作的顺序保存的,我想按速率排序并保持时间顺序,但是,我没有保存列表中的时间戳。简单地说,我只是想按比率对列表进行排序,并使评论保持相同的顺序。
    【解决方案3】:

    同时更改的文档 (relevant commit) 和 sorted 的当前文档明确保证:

    内置sorted()函数保证稳定。一个排序是稳定的,如果它保证不改变比较相等的元素的相对顺序——这有助于多次排序(例如,按部门排序,然后按薪级排序)。

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

    请注意,对于 CPython,list.sort 自 Python 2.3 以来一直保持稳定

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

    我不是 100% 确定 sorted,现在它简单地使用 list.sort,但我还没有检查历史。但它很可能“总是”使用list.sort。

    【讨论】:

      【解决方案4】:

      关于排序的 Python 3.6 文档现在指出

      保证排序是稳定的

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

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

      【讨论】:

        【解决方案5】:

        "What's New" docs for Python 2.4 有效地表明 sorted() 首先创建一个列表,然后在其上调用 sort(),为您提供所需的保证,尽管“官方”文档中没有。如果您真的担心,也可以只检查来源。

        【讨论】:

        • 你能指出它说的地方吗?它说 sorted()“像就地 list.sort() 一样工作”和“对新形成的副本进行排序”,但我没有看到它说它在内部使用 sort()。
        • 形成的“副本”是一个列表(这是您作为返回值得到的),并且在返回之前在该列表上调用 .sort()。 QED。不,这不是一个无懈可击的证据,但是在 Python 有一个官方标准之前,你不会得到那个。
        猜你喜欢
        • 2017-01-15
        • 2022-12-22
        • 1970-01-01
        • 2011-11-08
        • 1970-01-01
        • 1970-01-01
        • 2019-08-06
        • 1970-01-01
        • 2018-01-04
        相关资源
        最近更新 更多