Python3升序和降序排序

4
假设我有以下 Python 列表(这只是一个示例):
my_list = [{'user': 'Joe', 'score': 14},
           {'user': 'Foo', 'score': 12},
           {'user': 'May', 'score': 12},
           {'user': 'Kat', 'score': 12},
           {'user': 'Doe', 'score': 13}]

我需要将这个列表按照得分升序和用户名降序排序。 期望的排序结果:

my_list = [{'user': 'May', 'score': 12},
           {'user': 'Kat', 'score': 12},
           {'user': 'Foo', 'score': 12},
           {'user': 'Doe', 'score': 13},
           {'user': 'Joe', 'score': 14}]

如果我想让所有内容按升序排列,可以这样做:

my_list.sort(key=lambda x: (x['score'], x['user']))

对于整数,解决这个问题很容易,只需在其前面添加-

my_list.sort(key=lambda x: (-x['score'], x['user']))

很遗憾,字符串不能为负数 :-|
我需要一个通用解决方案,不涉及“reverse=True”。Lambda函数是基于用户配置动态生成的。
有什么想法吗?

可能是重复问题:https://dev59.com/UHI_5IYBdhLWcg3wHvU5 - myrdd
3个回答

4

如果你将 list.sortreverse 参数设置为 True,那么你当前的解决方案将可以正常工作:

>>> my_list = [{'user': 'Joe', 'score': 14},
...            {'user': 'Foo', 'score': 12},
...            {'user': 'May', 'score': 12},
...            {'user': 'Kat', 'score': 12},
...            {'user': 'Doe', 'score': 13}]
>>> my_list.sort(key=lambda x: (-x['score'], x['user']), reverse=True)
>>> pprint(my_list) # pprint makes the nice output
[{'score': 12, 'user': 'May'},
 {'score': 12, 'user': 'Kat'},
 {'score': 12, 'user': 'Foo'},
 {'score': 13, 'user': 'Doe'},
 {'score': 14, 'user': 'Joe'}]
>>>

这将以相反的顺序对列表进行排序。


编辑:

由于名称和分数具有两种不同的排序方式,您需要使用两个单独的排序来实现所需的输出:

>>> my_list = [{'user': 'Joe', 'score': 14},
...            {'user': 'Foo', 'score': 12},
...            {'user': 'May', 'score': 12},
...            {'user': 'Kat', 'score': 12},
...            {'user': 'Doe', 'score': 13}]
>>> my_list.sort(key=lambda x: x['user'], reverse=True)
>>> my_list.sort(key=lambda x: x['score'])
>>> pprint(my_list)
[{'score': 12, 'user': 'May'},
 {'score': 12, 'user': 'Kat'},
 {'score': 12, 'user': 'Foo'},
 {'score': 13, 'user': 'Doe'},
 {'score': 14, 'user': 'Joe'}]
>>>

它仅适用于这种特定情况,因为您可以玩弄整数值的符号。reverse=True会影响整个列表顺序,这是不可接受的。我需要一些可以影响特定列顺序的东西。就像在SQL中一样:按分数升序排列,用户降序排列,姓氏升序排列。 - Vlad Benya
请看我的编辑。在这种情况下,您需要使用两种排序(一种降序,另一种升序)。 - user2555451

2

字符串的ord值可以是负数:

my_list.sort(key=lambda x: (x["score"],[-ord(x) for x in x["user"]])))


In [50]:  my_list.sort(key=lambda x: (x["score"],[-ord(x) for x in x["user"]]))

In [51]: my_list
Out[51]: 
[{'score': 12, 'user': 'May'},
 {'score': 12, 'user': 'Kat'},
 {'score': 12, 'user': 'Foo'},
 {'score': 13, 'user': 'Doe'},
 {'score': 14, 'user': 'Joe'}]

哈哈!那绝对有效!但是它非常慢 :-| - Vlad Benya
@VladBenya,考虑到您不想使用reverse,要实现您想要的功能相当棘手,您可以以第一个字符-ord(x["user"][0])为妥协来完成。 - Padraic Cunningham

1
你需要添加 reverse=True 关键字以实现降序排列。
>>> my_list.sort(key=lambda x: (-x['score'], x['user']),reverse=True)
>>> my_list
[{'score': 12, 'user': 'May'}, {'score': 12, 'user': 'Kat'}, {'score': 12, 'user': 'Foo'}, {'score': 13, 'user': 'Doe'}, {'score': 14, 'user': 'Joe'}]

这只是一个为此示例定制的解决方案。我可能需要对三或四个字段进行排序。它们中的每一个都可以是降序,也可以是其他升序。所有字段都可以是字符串。我正在寻找一种通用解决方案。 - Vlad Benya
@VladBenya 你是什么意思?每次当你使用 reverse=True 时,sort 函数都会将可迭代对象进行反向排序! - Mazdak
@VladBenya 所以为了达到这个目的,你需要更新你的列表,而不能仅仅使用 sort - Mazdak
想象一下,score 是用户的姓氏,它是一个字符串。我想按照用户姓名升序排列这个列表,并按照他们的姓氏降序排列在一起。reverse=True 在这里不起作用,因为它会影响整个列表的最终顺序。 - Vlad Benya

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