Python按多个属性排序

3 投票
3 回答
1713 浏览
提问于 2025-04-16 07:44

我有一个字典,里面的内容大概是这样的。每一对键值就像是用户名:名字。

d = {"user2":"Tom Cruise", "user1": "Tom Cruise"}

我的问题是,我需要按照名字来排序这些内容。但是如果有多个用户的名字是一样的,我就需要再按照他们的用户名来排序。我查了一下排序的函数,但对里面的cmp参数和lambda表达式不是很明白。如果有人能给我解释一下这些,并帮我解决这个问题,那就太好了!谢谢 :)

3 个回答

0

你需要知道,字典(dict)是不能被排序的。不过在Python 2.7和3.1版本中,有一个叫做collections.OrderedDict的类。

所以,

>>> from collections import OrderedDict
>>> d=OrderedDict({'D':'X','B':'Z','C':'X','A':'Y'})
>>> d
OrderedDict([('A', 'Y'), ('C', 'X'), ('B', 'Z'), ('D', 'X')])
>>> OrderedDict(sorted((d.items()), key=lambda t:(t[1],t[0])))
OrderedDict([('C', 'X'), ('D', 'X'), ('A', 'Y'), ('B', 'Z')])
5

我来详细解释一下Ignacio Vazquez-Abrams的回答。cmp这个东西已经不推荐使用了,别再用了。用key属性代替它。

lambda是用来创建一个函数的。它是一种表达式,所以可以在一些普通的def语句不能用的地方使用,但它的内容只能是一条表达式。

my_func = lambda x: x + 1

这个定义了一个函数,它接受一个参数x,并返回x + 1lambda x, y=1: x + y定义了一个函数,它接受一个x参数,还有一个可选的y参数,默认值是1,并返回x + y。你可以看到,这其实和def语句很像,只不过它是一个表达式,并且内容只能是一条表达式。

key属性的作用是,sorted会对要排序的每个元素调用它,并使用它返回的值来进行比较。

list_ = ['a', 'b', 'c']
sorted(list_, key=lambda x: 1)

接下来看看一个假设的例子。我在写这个之前没有仔细看问题。不过这仍然是有教育意义的,所以我就留着了。 我们不能说太多,因为

  1. 你不能直接排序dict。你有一个dict的列表吗?我们可以对那个进行排序。
  2. 你没有展示username这个键。

我假设它是这样的

users = [{'name': 'Tom Cruise', 'username': user234234234, 'reputation': 1},
         {'name': 'Aaron Sterling', 'username': 'aaronasterling', 'reputation': 11725}]

如果你想确认我比汤姆·克鲁斯更厉害,你可以这样做:

sorted(users, key=lambda x: x['reputation'])

这只是传递了一个函数,它返回列表中每个字典的'reputation'值。但lambda可能会慢一些。大多数情况下,operator.itemgetter是你想要的。

operator.itemgetter接受一系列键,并返回一个函数,这个函数接受一个对象并返回一个包含其参数值的元组。

所以f = operator.itemgetter('name', 'username')基本上会返回和lambda d: (d['name'], d['username'])相同的函数。不同的是,原则上它运行得会快得多,而且你不需要看那些复杂的lambda表达式。

所以,要按名字和用户名对一个dict的列表进行排序,只需这样做:

sorted(list_of_dicts, operator.itemgetter('name', 'username'))

这正是Ignacio Vazquez-Abrams建议的。

6

cmp这个东西已经过时了。lambda只是用来创建一个函数。

sorted(d.iteritems(), key=operator.itemgetter(1, 0))

撰写回答