• Python 按照某个或某几个字段来排序字典列表


    1. 前言

    说到排序我们能想到的就是用sorted() 函数,并且可以通过key关键字参数来自定义排序的规则,假设下面是你从数据库里查询出来的网站会员信息列表:

    rows = [
        {'name': 'Jack', 'uid': 1003, 'level': 5},
        {'name': 'Gigi', 'uid': 1001, 'level': 2},
        {'name': 'Koko', 'uid': 1005, 'level': 3},
        {'name': 'Eric', 'uid': 1004, 'level': 2},
        {'name': 'Aven', 'uid': 1002, 'level': 6}
    ]
    

    下面会演示两种方式来实现排序,lambda和itemgetter(),但是事先说明,使用itemgetter()方式运行会稍微快点,所以如果对性能要求较高的话就是用itemgetter()方式。

    2. lambda表达式

    sorted()函数可以结合 lambda 表达式实现对指定字典列表字段的排序:

    # 根据name排序
    rows_by_name = sorted(rows, key=lambda r: r['name'])
    # 根据uid排序
    rows_by_uid = sorted(rows, key=lambda r: r['uid'])
    print(rows_by_name)
    print(rows_by_uid)
    

    执行结果:

    [{'name': 'Aven', 'uid': 1002, 'level': 6}, {'name': 'Eric', 'uid': 1004, 'level': 2}, {'name': 'Gigi', 'uid': 1001, 'level': 2}, {'name': 'Jack', 'uid': 1003, 'level': 5}, {'name': 'Koko', 'uid': 1005, 'level': 3}]
    [{'name': 'Gigi', 'uid': 1001, 'level': 2}, {'name': 'Aven', 'uid': 1002, 'level': 6}, {'name': 'Jack', 'uid': 1003, 'level': 5}, {'name': 'Eric', 'uid': 1004, 'level': 2}, {'name': 'Koko', 'uid': 1005, 'level': 3}]
    

    3. itemgetter函数

    使用 operator 模块的 itemgetter 函数,我们的sorted()函数可以结合它很容易的实现对字典列表字段的排序,至少比lambda简单很多。

    from operator import itemgetter
    rows_by_name = sorted(rows, key=itemgetter('name'))
    rows_by_uid = sorted(rows, key=itemgetter('uid'))
    print(rows_by_name)
    print(rows_by_uid)
    

    执行结果:

    [{'name': 'Aven', 'uid': 1002, 'level': 6}, {'name': 'Eric', 'uid': 1004, 'level': 2}, {'name': 'Gigi', 'uid': 1001, 'level': 2}, {'name': 'Jack', 'uid': 1003, 'level': 5}, {'name': 'Koko', 'uid': 1005, 'level': 3}]
    [{'name': 'Gigi', 'uid': 1001, 'level': 2}, {'name': 'Aven', 'uid': 1002, 'level': 6}, {'name': 'Jack', 'uid': 1003, 'level': 5}, {'name': 'Eric', 'uid': 1004, 'level': 2}, {'name': 'Koko', 'uid': 1005, 'level': 3}]
    

    itemgetter() 函数也支持多个keys,比如下面代码:

    rows_by_lname = sorted(rows, key=itemgetter('name','level'))
    print(rows_by_uname)
    

    执行结果:

    [{'name': 'Aven', 'uid': 1002, 'level': 6}, {'name': 'Eric', 'uid': 1004, 'level': 2}, {'name': 'Gigi', 'uid': 1001, 'level': 2}, {'name': 'Jack', 'uid': 1003, 'level': 5}, {'name': 'Koko', 'uid': 1005, 'level': 3}]
    

    rows 会被传递给只接受一个关键字参数(key=xx)的sorted()内置函数,这个参数是callable类型,并且会从rows中接受一个单一元素,然后返回被用来排序的值,itemgetter()函数就是专门负责创建这个callable对象。

    4. 性能测试

    我刚在上面提到了itemgetter()性能更好,那有同学会问?你怎么知道的,我们来看下面的性能测试就知道结果了:

    >>> import dis
    >>> rows = [
    ...     {'name': 'Jack', 'uid': 1003, 'level': 5},
    ...     {'name': 'Gigi', 'uid': 1001, 'level': 2},
    ...     {'name': 'Koko', 'uid': 1005, 'level': 3},
    ...     {'name': 'Eric', 'uid': 1004, 'level': 2},
    ...     {'name': 'Aven', 'uid': 1002, 'level': 6}
    ... ]
    
    # 测试lambda性能
    >>> x = lambda: sorted(rows, key=lambda r: r['name'])
    >>> dis.dis(x)
      1           0 LOAD_GLOBAL              0 (sorted)
                  2 LOAD_GLOBAL              1 (rows)
                  4 LOAD_CONST               1 (<code object <lambda> at 0x1047cb920, file "<stdin>", line 1>)
                  6 LOAD_CONST               2 ('<lambda>.<locals>.<lambda>')
                  8 MAKE_FUNCTION            0
                 10 LOAD_CONST               3 (('key',))
                 12 CALL_FUNCTION_KW         2
                 14 RETURN_VALUE
    
    Disassembly of <code object <lambda> at 0x1047cb920, file "<stdin>", line 1>:
      1           0 LOAD_FAST                0 (r)
                  2 LOAD_CONST               1 ('name')
                  4 BINARY_SUBSCR
                  6 RETURN_VALUE
                    
    # 测试itemgetter性能
    >>> from operator import itemgetter
    >>> y = lambda: sorted(rows, key=itemgetter('name'))
    >>> dis.dis(y)
      1           0 LOAD_GLOBAL              0 (sorted)
                  2 LOAD_GLOBAL              1 (rows)
                  4 LOAD_GLOBAL              2 (itemgetter)
                  6 LOAD_CONST               1 ('name')
                  8 CALL_FUNCTION            1
                 10 LOAD_CONST               2 (('key',))
                 12 CALL_FUNCTION_KW         2
                 14 RETURN_VALUE
    

    可以很明显的看到 lambda 执行的步骤比 itemgetter 多了很多,所以 itemgetter 性能胜出。

  • 相关阅读:
    【Git】rebase 用法小结(转)
    修饰符访问权限。
    throws与throw关键字。
    多线程,同步代码块。
    多线程,设置线程的优先级。
    多线程,加入线程。
    多线程,守护线程。
    多线程,休眠线程。
    多线程,获取当前线程的对象。
    多线程获取名字和设置名字。
  • 原文地址:https://www.cnblogs.com/jasonminghao/p/13246582.html
Copyright © 2020-2023  润新知