文章首發於知乎專欄,歡迎關注。
zhuanlan.zhihu.com/pythoncookb…python
如下測試代碼所有基於 Python3。bash
Python 提供了大量的內置數據結構,包括列表,集合以及字典。在工做和編碼中,能夠說每天和它們打交道,常常碰到查詢,排序和過濾等等這些問題,雖然每次解決這些問題並不困難,但總感受代碼寫的很麻煩,不夠優雅。微信
最近經過閱讀《Python3 CookBook》,瞭解了一些更優秀的方法,作一些簡單記錄,與你們分享。數據結構
咱們都知道,一個序列是能夠賦值給多個變量的,就像下面這樣:app
In [7]: p = (1, 2, 3)
In [8]: x, y, z = p
In [9]: x
Out[9]: 1複製代碼
但若是接收的變量個數和序列元素個數不一致,就會報錯,若是你不知道元素個數的話,能夠採用下面這樣的方式:函數
In [10]: x, *y = p
In [11]: y
Out[11]: [2, 3]複製代碼
經過這種星號的方式,就能夠解壓不肯定個數或任意個數的可迭代對象了,是否是很棒呢?測試
那麼,用這個方法能夠解決哪些問題呢?優化
先來看一種狀況,如今有一個序列,去掉第一個數和最後一個數,而後求剩下數的平均值。ui
這個問題很簡單,個人第一反應是循環求和,而後計算平均值,顯然很麻煩。這時候星號表達式就派上用場了:編碼
def drop_first_last(items):
first, *middle, last = items
return avg(middle)複製代碼
再看一種狀況,好比字符串的分割:
In [12]: line = 'drwxr-xr-x 41 zyx staff 1.4K 11 24 08:53 zyx'
In [13]: info, *fields, homedir = line.split(' ')
In [14]: info
Out[14]: 'drwxr-xr-x'
In [15]: homedir
Out[15]: 'zyx'複製代碼
這個問題也是常常會遇到的,好比只取文件中知足要求的前五行,或者只返回知足要求的最新十條數據。個人第一反應是列表,而後經過 push 和 pop 來操做列表來實現。
其實經過 collections.deque 能夠很容易解決這個問題,使用 deque(maxlen=N) 構造函數新建一個固定大小的隊列。當新元素加入而且這個隊列已滿時,最早進入隊列的元素便會被移除,符合先進先出的原則。
In [16]: from collections import deque
In [17]: q = deque(maxlen=3)
In [18]: q.append(1)
In [19]: q.append(2)
In [20]: q.append(3)
In [21]: q
Out[21]: deque([1, 2, 3])
In [22]: q.append(4)
In [23]: q
Out[23]: deque([2, 3, 4])複製代碼
若是沒有設置 maxlen 則是一個無限大小的隊列,能夠經過 appendleft 和 pop 在隊首和隊尾添加刪除元素。
如今有一個需求,構建一個字典,key 是用戶 ID,value 爲一個列表,列表元素能夠是名字,電話等等,大概是這樣:
d = {'id': ['name', 'phone']}複製代碼
若是咱們本身構建這個字典,可能會像下面這樣來實現:
d = {}
for key, value in items:
if key not in d:
d[key] = value
d[key].append(value)複製代碼
很麻煩,若是使用 collections 的 defaultdict 就很簡單了。defaultdict 的一個特徵就是它會自動初始化每一個 key 剛開始對應的值,因此咱們只關注添加元素操做就能夠了。
優化後代碼就變成了這樣:
d = defaultdict(list)
for key, value in items:
d[key].append(value)複製代碼
字典是無序的,但若是要控制字典中元素的順序呢?可使用 colletions 中的 OrderedDict,以下:
d = OrderedDict()
d['foo'] = 1
d['bar'] = 2
d['spam'] = 3
d['grok'] = 4
# Outputs "foo 1", "bar 2", "spam 3", "grok 4"
for key in d:
print(key, d[key])複製代碼
OrderedDict 內部維護這一個根據鍵插入順序排序的雙向鏈表。每次新元素插入時,便會被放在鏈表尾部,對於已經存在的鍵,並不會改變鍵的順序。
但須要注意的是,OrderedDict 的大小是普通字典的兩倍,因此在構建一個須要大量 OrderedDict 實例的數據結構時,就要考慮大量內存消耗的影響了。
如何取出字典中的最小值,或者對字典進行排序呢?
首先咱們來看看直接使用普通的數學運算函數
In [25]: d = {'a': 11, 'b': 43, 'c': 3, 'd': 65}
In [26]: min(d)
Out[26]: 'a'複製代碼
它比較的邏輯是直接比較 key,而後取出對應的 key,但若是要比較 value 呢?
In [28]: min(d.values())
Out[28]: 3複製代碼
結果是正確的,但彷佛並不完美,若是鍵值一塊兒返回就完美了。這時候就該 zip 登場了,它的做用是可使鍵和值反轉過來。
In [29]: min(zip(d.values(), d.keys()))
Out[29]: (3, 'c')複製代碼
它直接返回了值最小的鍵和值,這樣就很好了,無論須要哪一個信息均可以直接使用。若是要對這個字典排序的話也很簡單:
In [34]: sorted(zip(d.values(), d.keys()))
Out[34]: [(3, 'c'), (11, 'a'), (43, 'b'), (65, 'd')]複製代碼
先寫這麼多吧,未完待續。。。
歡迎留言,或者添加我我的微信 zhangyx6a 交流溝通,不是微商。