如何按第二个项目降序和第一个项目升序对列表进行排序?

3

我有一个类似这样的列表:

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), ]
2个回答

2
您想按照两个标准排序,其中一个标准作为另一个标准的决定因素。由于Python的sortedlist.sort都保证是稳定排序,一种解决方法是将列表排序两次:先按决定因素排序,然后按主要标准排序。这是@Bharel的答案。 另一种可能性是仅排序一次,使用元组作为关键字。Python的sortedlist.sort都提供了一个reverse=True或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)个字符串比较。
如果你的列表很小,那么哪个版本更快可能并不重要(除非你反复排序许多小列表……),所以这是一种偏好和可读性问题。

1
首先按照第一项排序,然后按照第二项排序:
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。它是一种稳定算法,这意味着如果两个值相同,它们将保持原始顺序。
如果您先按字母顺序排序,然后再按优先级排序,列表将根据字母表顺序排序,然后按优先级重新排序,其中字母表是次要的。

1
@Stef 我想向 OP 显示他的思考方式是正确的,然后向他展示最佳方法。 - Bharel
这里有点混淆。如果您使用某个键排序,然后再使用另一个键进行第二次排序,您不能说第二次排序是“O(n)”,因为从第二个排序键的角度来看,数据根本没有排序。 - Stef
1
两者中哪个更快可能取决于列表的大小。每个项目只计算一次键,所以排序两次可能比仅排序一次要慢。比较元组键可能比比较整数键慢,但使用元组的好处是只有在整数相等时才需要比较字符串 - 而如果你排序两次,你确实需要比较很多字符串(而字符串比较比整数比较慢)。所以如果列表很长且字符串也可能很长,我会选择使用带有元组键的单次排序。 - Stef
1
当然,只有实际的定时实验才能决定它 - 但结果可能取决于数据(列表长度,字符串长度,字符串中公共前缀的长度等)。 - Stef
1
测试表明,在包含5-10个随机字母和1-10范围内数字的500个字符串中,我的解决方案能够承受。超过500个字符串或更大数量的变化,您的解决方案会更好,而在此之下,我的解决方案似乎更好。我认为您完全正确,只需要一个排序会在以后产生很大的差异,因为lambda的规模是O(n)const,而双重排序则需要O(nlogn)。请将其作为可能的答案添加 :-) - Bharel
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接