1. 程式人生 > >Python中列表(list)、字典(dict)排序的程序

Python中列表(list)、字典(dict)排序的程序

self. 能夠 網站 軟件 too 字段 tool 生成 ted

Python3 中的排序,在 Sorting HOW TO 中已經講得很清楚了。來個實際的例子,對下面的這個 list 依據創建時間排序:

pages = [
{‘title‘: ‘十年學會程序設計‘, ‘time‘: ‘2012-02-14‘, ‘name‘: ‘21-days‘},
{‘title‘: ‘ANE Toolkit‘, ‘time‘: ‘2012-06-07‘, ‘name‘: ‘anetoolkit‘},
{‘title‘: ‘cocos2d-x-filters‘, ‘time‘: ‘2015-05-06‘, ‘name‘: ‘cocos2d-x-filters‘},
{‘title‘: ‘我的Firefox插件‘, ‘time‘: ‘2006-05-23‘, ‘name‘: ‘firefox-addons‘},

{‘title‘: ‘Flash&Flex大全‘, ‘time‘: ‘2005-11-02‘, ‘name‘: ‘flashassistant‘},
{‘title‘: ‘提問的智慧‘, ‘time‘: ‘2005-10-08‘, ‘name‘: ‘howtoask‘},
{‘title‘: ‘Linux軟件‘, ‘time‘: ‘2009-04-30‘, ‘name‘: ‘linux-software‘},
{‘title‘: ‘Platform ANEs‘, ‘time‘: ‘2013-08-22‘, ‘name‘: ‘platform-anes‘},
{‘title‘: ‘閱讀‘, ‘time‘: ‘2015-03-03‘, ‘name‘: ‘read‘},
{‘title‘: ‘Sprite Sheet Editor‘, ‘time‘: ‘2011-08-18‘, ‘name‘: ‘sprite_sheet_editor‘},
{‘title‘: ‘SpriteSheetPacker‘, ‘time‘: ‘2011-04-19‘, ‘name‘: ‘spritesheetpacker‘},
{‘title‘: ‘WordPress大全‘, ‘time‘: ‘2006-03-07‘, ‘name‘: ‘wordpressfavorite‘},
{‘title‘: ‘WPCMD‘, ‘time‘: ‘2015-06-12‘, ‘name‘: ‘wpcmd‘}
]
首先,排序需要一個可以比較的對象,我使用鍵名為 index 中的對象:

from datetime import date

for item in pages:
t = item[‘time‘].split(‘-‘)
item[‘index‘] = date(int(t[0]), int(t[1]), int(t[2]))
date 的實例是可比較的(它實現了 __lt__ 那一套方法), date(2012,2,14) < data(2005, 11, 2) == False 。

然後,對 pages 調用 sort 方法:

pages.sort(key=lambda item : item[‘index‘])
在這裏,我需要為 key 傳遞一個函數,這個函數能返回需要比較的值。

當然,也可以使用 operator 提供的 itemgetter 方法來獲取這個待比較的值。

from operator import itemgetter
names.sort(key=itemgetter(‘index‘))
除了 itemgetter 之外, operator 模塊還提供了 attrgetter 和 methodcaller 。

張賀 對上面提到的 Sorting Mini-HOW TO 做了一些必要的中文評註,該文和 Sorting HOW TO 基本相同。

通過某個關鍵字排序一個字典列表

通過使用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()函數也支持多個keys,比如下面的代碼

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‘}]

討論
在上面例子中,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()等函數。比如:

>>> min(rows, key=itemgetter(‘uid‘))
{‘fname‘: ‘John‘, ‘lname‘: ‘Cleese‘, ‘uid‘: 1001}
>>> max(rows, key=itemgetter(‘uid‘))
{‘fname‘: ‘Big‘, ‘lname‘: ‘Jones‘, ‘uid‘: 1004}
>>>


排序不支持原生比較的對象

內置的 sorted() 函數有一個關鍵字參數 key ,可以傳入一個 callable 對象給它, 這個 callable 對象對每個傳入的對象返回一個值,這個值會被 sorted 用來排序這些對象。 比如,如果你在應用程序裏面有一個User實例序列,並且你希望通過他們的user_id屬性進行排序, 你可以提供一個以User實例作為輸入並輸出對應user_id值的 callable 對象。比如:

class User:
def __init__(self, user_id):
self.user_id = user_id

def __repr__(self):
return ‘User({})‘.format(self.user_id)


def sort_notcompare():
users = [User(23), User(3), User(99)]
print(users)
print(sorted(users, key=lambda u: u.user_id))
另外一種方式是使用 operator.attrgetter() 來代替lambda函數:

>>> from operator import attrgetter
>>> sorted(users, key=attrgetter(‘user_id‘))
[User(3), User(23), User(99)]
>>>

討論
選擇使用lambda函數或者是 attrgetter() 可能取決於個人喜好。 但是,attrgetter() 函數通常會運行的快點,並且還能同時允許多個字段進行比較。 這個跟 operator.itemgetter() 函數作用於字典類型很類似(參考1.13小節)。 例如,如果User實例還有一個first_name和last_name屬性,那麽可以向下面這樣排序:

by_name = sorted(users, key=attrgetter(‘last_name‘, ‘first_name‘))
同樣需要註意的是,這一小節用到的技術同樣適用於像 min() 和 max() 之類的函數。比如:

>>> min(users, key=attrgetter(‘user_id‘)
User(3)
>>> max(users, key=attrgetter(‘user_id‘)
User(99)
>>>

Python中列表(list)、字典(dict)排序的程序