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 性能勝出。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM