通过某个关键字排序一个字典列表
解决方案:
通过使用 operator 模块的 itemgetter 函数,可以非常容易的排序这样的数据结构。 假
设你从数据库中检索出来网站会员信息列表,并且以下列的数据结构返回:
rows = [
{'fname': 'Brian', 'lname': 'Jones', 'uid': 1003},
{'fname': 'David', 'lname': 'Beazley', 'uid': 1002},
{'fname': 'John', 'lname': 'Cleese', 'uid': 1001},
{'fname': 'Big', 'lname': 'Jones', 'uid': 1004}
]
根据
任意的字典字段来排序输入结果行是很容易实现的,代码示例:
# encoding:utf-8
# usr/bin/python
from operator import itemgetter
rows = [
{'fname': 'Brian', 'lname': 'Jones', 'uid': 1003},
{'fname': 'David', 'lname': 'Beazley', 'uid': 1002},
{'fname': 'John', 'lname': 'Cleese', 'uid': 1001},
{'fname': 'Big', 'lname': 'Jones', 'uid': 1004}
]
rows_by_fname = sorted(rows, key=itemgetter('fname'))
rows_by_uid = sorted(rows, key=itemgetter('uid'))
print(rows_by_fname)
print(rows_by_uid)
代码输出如下:
[{'lname': 'Jones', 'uid': 1004, 'fname': 'Big'}, {'lname': 'Jones', 'uid': 1003, 'fname': 'Brian'}, {'lname': 'Beazley', 'uid': 1002, 'fname': 'David'}, {'lname': 'Cleese', 'uid': 1001, 'fname': 'John'}]
[{'lname': 'Cleese', 'uid': 1001, 'fname': 'John'}, {'lname': 'Beazley', 'uid': 1002, 'fname': 'David'}, {'lname': 'Jones', 'uid': 1003, 'fname': 'Brian'}, {'lname': 'Jones', 'uid': 1004, 'fname': 'Big'}]
itemgetter() 函数也支持多个keys,比如下面的代码
rows_by_lfname = sorted(rows, key=itemgetter('lname', 'fname'))
print(rows_by_lfname)
会产生如下的输出:
[{'lname': 'Beazley', 'uid': 1002, 'fname': 'David'}, {'lname': 'Cleese', 'uid': 1001, 'fname': 'John'}, {'lname': 'Jones', 'uid': 1004, 'fname': 'Big'}, {'lname': 'Jones', 'uid': 1003, 'fname': 'Brian'}]
讨论
在上面例子中, rows 被传递给接受一个关键字参数的 sorted() 内置函数。 这个参数是
callable 类型,并且从 rows 中接受一个单一元素,然后返回被用来排序的值。
itemgetter() 函数就是负责创建这个 callable 对象的。
operator.itemgetter() 函数有一个被rows中的记录用来查找值的索引参数。可以是一个
字典键名称, 一个整形值或者任何能够传入一个对象的 __getitem__() 方法的值。 如果
你传入多个索引参数给 itemgetter() ,它生成的 callable 对象会返回一个包含所有元素
值的元组, 并且 sorted() 函数会根据这个元组中元素顺序去排序。 但你想要同时在几个
字段上面进行排序(比如通过姓和名来排序,也就是例子中的那样)的时候这种方法是很有
用的。
itemgetter() 有时候也可以用 lambda 表达式代替,比如:
rows_by_fname = sorted(rows, key=lambda r: r['fname'])
rows_by_lfname = sorted(rows, key=lambda r: (r['lname'], r['fname']))
这种方案也不错。但是,使用 itemgetter() 方式会运行的稍微快点。因此,如果你对性
能要求比较高的话就使用 itemgetter() 方式。
这节中展示的技术也同样适用于 min() 和 max() 等函数。比如:
print (min(rows, key=itemgetter('uid')))
print (max(rows, key=itemgetter('uid')))
输出字典列表uid最小的一组和最大的一组
{'lname': 'Cleese', 'uid': 1001, 'fname': 'John'}
{'lname': 'Jones', 'uid': 1004, 'fname': 'Big'}
最后,列表字典的排序可以生成一种方法:
def mysortedByKeyList(dict_list, dict_key, rev=False):
"""列表字典按字典里面的列表key来排序
@param dict_list: list字典列表
@param dict_key: list字典排序的key列表(dict_list可不存在该key)
@param rev:bool 是否倒序,Flase为升序,True为降序"""
dict_list.sort(key=lambda x: tuple(x.get(ca) for ca in dict_key), reverse=rev)
return dict_list
调用:
dict_key = ["lname", "fname"] # 需要根据的key列表进行排序,支持某些不存在的key字典列表进行排序
print mysortedByKeyList(rows, dict_key)
输出
[{'lname': 'Beazley', 'uid': 1002, 'fname': 'David'}, {'lname': 'Cleese', 'uid': 1001, 'fname': 'John'}, {'lname': 'Jones', 'uid': 1004, 'fname': 'Big'}, {'lname': 'Jones', 'uid': 1003, 'fname': 'Brian'}]