《Python Cookbook(第3版)中文版》——1.13 通过公共键对字典列表排序

    xiaoxiao2024-01-23  165

    本节书摘来自异步社区《Python Cookbook(第3版)中文版》一书中的第1章,第1.13节,作者[美]David Beazley , Brian K.Jones,陈舸 译,更多章节内容可以访问云栖社区“异步社区”公众号查看。

    1.13 通过公共键对字典列表排序

    1.13.1 问题

    我们有一个字典列表,想根据一个或多个字典中的值来对列表排序。

    1.13.2 解决方案

    利用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} ]

    根据所有的字典中共有的字段来对这些记录排序是非常简单的,示例如下:

    from operator import itemgetter rows_by_fname = sorted(rows, key=itemgetter('fname')) rows_by_uid = sorted(rows, key=itemgetter('uid')) print(rows_by_fname) print(rows_by_uid)

    以上代码的输出为:

    [{'fname': 'Big', 'uid': 1004, 'lname': 'Jones'}, {'fname': 'Brian', 'uid': 1003, 'lname': 'Jones'}, {'fname': 'David', 'uid': 1002, 'lname': 'Beazley'}, {'fname': 'John', 'uid': 1001, 'lname': 'Cleese'}] [{'fname': 'John', 'uid': 1001, 'lname': 'Cleese'}, {'fname': 'David', 'uid': 1002, 'lname': 'Beazley'}, {'fname': 'Brian', 'uid': 1003, 'lname': 'Jones'}, {'fname': 'Big', 'uid': 1004, 'lname': 'Jones'}]

    itemgetter()函数还可以接受多个键。例如下面这段代码:

    rows_by_lfname = sorted(rows, key=itemgetter('lname','fname')) print(rows_by_lfname)

    这会产生如下的输出:

    [{'fname': 'David', 'uid': 1002, 'lname': 'Beazley'}, {'fname': 'John', 'uid': 1001, 'lname': 'Cleese'}, {'fname': 'Big', 'uid': 1004, 'lname': 'Jones'}, {'fname': 'Brian', 'uid': 1003, 'lname': 'Jones'}]

    1.13.3 讨论

    在这个例子中,rows被传递给内建的sorted()函数,该函数接受一个关键字参数key。这个参数应该代表一个可调用对象(callable),该对象从rows中接受一个单独的元素作为输入并返回一个用来做排序依据的值。itemgetter()函数创建的就是这样一个可调用对象。

    函数operator.itemgetter()接受的参数可作为查询的标记,用来从rows的记录中提取出所需要的值。它可以是字典的键名称、用数字表示的列表元素或是任何可以传给对象的__getitem__()方法的值。如果传多个标记给itemgetter(),那么它产生的可调用对象将返回一个包含所有元素在内的元组,然后sorted()将根据对元组的排序结果来排列输出结果。如果想同时针对多个字段做排序(比如例子中的姓和名),那么这是非常有用的。

    有时候会用lambda表达式来取代itemgetter()的功能。例如:

    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()这样的函数。例如:

    >>> min(rows, key=itemgetter('uid')) {'fname': 'John', 'lname': 'Cleese', 'uid': 1001} >>> max(rows, key=itemgetter('uid')) {'fname': 'Big', 'lname': 'Jones', 'uid': 1004} >>> 相关资源:python cookbook(第3版)
    最新回复(0)