Python按多个属性排序
我有一个字典,里面的内容大概是这样的。每一对键值就像是用户名:名字。
d = {"user2":"Tom Cruise", "user1": "Tom Cruise"}
我的问题是,我需要按照名字来排序这些内容。但是如果有多个用户的名字是一样的,我就需要再按照他们的用户名来排序。我查了一下排序的函数,但对里面的cmp参数和lambda表达式不是很明白。如果有人能给我解释一下这些,并帮我解决这个问题,那就太好了!谢谢 :)
3 个回答
你需要知道,字典(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')])
我来详细解释一下Ignacio Vazquez-Abrams的回答。cmp
这个东西已经不推荐使用了,别再用了。用key
属性代替它。
lambda
是用来创建一个函数的。它是一种表达式,所以可以在一些普通的def
语句不能用的地方使用,但它的内容只能是一条表达式。
my_func = lambda x: x + 1
这个定义了一个函数,它接受一个参数x
,并返回x + 1
。lambda x, y=1: x + y
定义了一个函数,它接受一个x
参数,还有一个可选的y
参数,默认值是1,并返回x + y
。你可以看到,这其实和def
语句很像,只不过它是一个表达式,并且内容只能是一条表达式。
key
属性的作用是,sorted
会对要排序的每个元素调用它,并使用它返回的值来进行比较。
list_ = ['a', 'b', 'c']
sorted(list_, key=lambda x: 1)
接下来看看一个假设的例子。我在写这个之前没有仔细看问题。不过这仍然是有教育意义的,所以我就留着了。
我们不能说太多,因为
- 你不能直接排序
dict
。你有一个dict
的列表吗?我们可以对那个进行排序。 - 你没有展示
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建议的。
cmp
这个东西已经过时了。lambda
只是用来创建一个函数。
sorted(d.iteritems(), key=operator.itemgetter(1, 0))