Pythonは、辞書リストを1つまたは複数のフィールドでソートします.

5806 ワード

目次
  • 1. 前言
  • 2. Lambda式
  • 3. itemgetter関数
  • 4. パフォーマンステスト
  • 1.はじめに
    ソートといえばsorted()関数を使用し、keyキーワードパラメータを使用してソートのルールをカスタマイズすることができます.次に、データベースからクエリーしたWebサイトの会員情報のリストを仮定します.
    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}
    ]
    

    ソートを実現する2つの方法、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は、1つのキーワードパラメータ(key=xx)のみを受け入れるsorted()内蔵関数に渡されます.このパラメータはcallableタイプであり、rowsから1つの要素を受け入れ、ソートに使用される値を返します.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 ( at 0x1047cb920, file "", line 1>)
                  6 LOAD_CONST               2 ('..')
                  8 MAKE_FUNCTION            0
                 10 LOAD_CONST               3 (('key',))
                 12 CALL_FUNCTION_KW         2
                 14 RETURN_VALUE
    
    Disassembly of  at 0x1047cb920, file "", 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の性能が優れていることが明らかになった.