【问题标题】:How can i sort a list by the second item descending and first one ascending?如何按第二项降序和第一项升序对列表进行排序?
【发布时间】:2022-01-15 17:58:36
【问题描述】:

我有一个这样的列表:

list_results=[('Horror', 2), ('Romance', 2), ('Comedy', 2), ('History', 2), ('Adventure', 1), ('Action', 3)]

我希望对数字进行降序排序,如果数字相同,则按照名称升序排序。

我尝试了以下代码:

sortlist=sorted(list_results,key=lambda x:(x[1],x[0]))

反之,但我想不通。

我正在寻找的答案是:

[('Action', 3), ('Comedy', 2) ,('History', 2),('Horror', 2), ('Romance', 2), ('Adventure', 1), ]

【问题讨论】:

    标签: python sorting stable-sort


    【解决方案1】:

    您想根据两个标准进行排序,其中一个标准充当另一个标准的决胜局。由于 python 的 sortedlist.sort 保证是稳定的排序,一个解决方案是对列表进行两次排序:首先按 tie-breaker 排序,然后按主要标准排序。 This is @Bharel's answer.

    另一种可能性是只排序一次,使用元组作为键。 Python 的sortedlist.sort 都提供reverse= True or False 参数来指定按升序或降序排序;但是在您的情况下,我们希望根据第一个标准按降序排序,并根据第二个标准按升序排序。 reverse 关键字没有帮助,因为它是全有或全无:它不允许我们选择要反转的标准。

    由于第一个标准是数字(整数),因此以相反顺序排序的一个简单技巧是用减号取反:

    sortlist = sorted(list_results, key=lambda x:(-x[1], x[0]))
    

    注意-x[1] 而不是x[1]

    这里有两个论点支持按元组排序一次,而不是两次:

    • 当按照(-x[1], x[0])排序时,马上就清楚-x[1]是主要标准,x[0]只是一个平局。相比之下,如果您排序两次,阅读您的代码的人需要花一秒钟的时间来理解最后一个排序是最重要的,而前一个排序只是作为一个决胜局,依赖于sorted 是一个稳定的排序。
    • 如果列表很长,使用元组键排序一次可能比使用简单键排序两次更快。尤其如此,因为第二个键是字符串;比较字符串比比较整数慢。如果您使用元组,则字符串将仅针对第一个键上相等的两个项目进行比较;但是如果你排序两次,大约n log(n)的字符串比较将在第一次排序中进行。

    如果您的列表很小,那么哪个版本更快可能并不重要(除非您反复对许多小列表进行排序......),所以这是一个偏好和可读性的问题。

    【讨论】:

      【解决方案2】:

      先按第一项排序,再按第二项排序:

      list_results = sorted(list_results, key=lambda x:x[0])
      list_results = sorted(list_results, key=lambda x:x[1], reverse=True)
      

      或者更好的是不复制:

      import operator
      
      list_results.sort(key=operator.itemgetter(0))
      list_results.sort(key=operator.itemgetter(1), reverse=True)
      

      Python 的排序算法是Timsort。这是一个stable algorithm,意思是如果两个值相同,它们将保持原来的顺序。

      如果先按字母排序,再按优先级排序,列表会先按字母排序,再按优先级重新排序,字母次之。

      【讨论】:

      • ""或者更好,但不复制:" 是的,第二个版本更好。如果你要丢弃无论如何,原始列表。如果您不想丢弃原始列表,您可以做什么,第一次使用sorted,然后第二次使用.sort
      • @Stef 我想向 OP 展示他的思维方式是正确的,然后向他展示最好的方式。
      • 两者哪个更快可能取决于列表的大小。每个项目只计算一次键,因此排序两次可能比只排序一次慢。比较元组键可能比比较整数键慢,但是使用元组还有一个额外的好处,即仅在整数上存在平局时才需要比较字符串 - 而如果您排序两次,您确实需要比较很多字符串(并且字符串比较比整数比较慢)。因此,如果列表很长并且字符串也可能很长,那么我的钱是使用元组键进行单次排序。
      • 当然只有实际的定时实验才能决定——但结果可能取决于数据(列表的长度、字符串的长度、字符串中常见前缀的长度等)跨度>
      • 测试证明,在包含 5-10 个随机字母和 1-10 范围内的数字的 500 个字符串中达到平衡。超过 500 个字符串或对于更大的数字种类,您的解决方案可以更好地扩展,低于我的解决方案似乎更好。我相信你完全正确,只需要一种排序会在以后产生很大的不同,因为 lambda 在 O(n) * const 上缩放,而双重排序适用于 O(n*logn)。请将其添加为可能的答案:-)
      猜你喜欢
      • 2017-02-17
      • 1970-01-01
      • 1970-01-01
      • 2016-10-18
      • 1970-01-01
      • 2016-10-18
      • 2020-11-09
      • 1970-01-01
      相关资源
      最近更新 更多