本文始發於我的公衆號:TechFlow,原創不易,求個關注程序員
今天是Python專題的第8篇文章。web
今天咱們依然介紹的是迭代器,不過介紹的是幾個比較經常使用的高級用法,在實際場景當中很是實用,能夠幫助咱們大大簡化代碼的複雜度。數組
首先是跳過開始部分,這個在咱們讀取文本的時候最經常使用。在實際的應用當中,好比記錄的日誌或者是代碼等等,通常來講頭部都會附上一段說明,或者用註釋標註或者是用特殊的符號標記。這些信息是給用到數據的程序員看的,當咱們經過代碼獲取數據的時候,顯然是但願能夠過濾掉這些信息的。編輯器
好比咱們有一段數據,它的開頭用#作了一些註釋:函數
# This is a data for student
# Rows 100
xiaoming, 17, 99;
xiaoli, 18, 98;
...
複製代碼
常規操做當中,咱們會建立一個打開文件的迭代器,咱們經過遍歷這個迭代器去獲取文件當中的數據:工具
with open('xxxx.txt') as f:
for line in f:
print(line)
複製代碼
若是隻是用來輸出還好,若是咱們須要加工文件當中的數據,那麼頭部的註釋信息就會干擾咱們代碼的運行。咱們固然能夠手動加入一些判斷,可是這會比較麻煩,代碼也不夠美觀。針對這個問題,一個比較好的解決方案是dropwhile。this
dropwhile是itemtools當中的一個函數,它能夠接收一個咱們自定義的過濾函數和迭代器從新生成一個新的迭代器,這個新的迭代器當中會過濾掉以前迭代器頭部不符合咱們要求的數據:spa
在剛纔的例子當中咱們想要過濾掉頭部加了#註釋的部分,咱們能夠這麼操做:日誌
from itertools import dropwhile
with open('xxxx.txt') as f:
for line in dropwhile(lambda line: line.startswith('#'), f):
print(line)
複製代碼
這樣出來的結果就沒有頭部咱們不須要的內容了。code
當咱們知道頭部不符合狀況的數據的格式的時候,可使用dropwhile來規定過濾的格式。若是咱們知道須要過濾的條數,則可使用另一個工具,叫作islice,它的本質是一個切片函數,就像是Python當中數組的切片功能同樣,能夠切出迭代器當中指定片斷的數據。
舉個例子:
from itertools import dropwhile
with open('xxxx.txt') as f:
for line in islice(f, 3, None):
print(line)
複製代碼
這樣咱們就會從第三行開始獲取,以前的數據會被過濾掉。它其實就表明着數組當中[3: ]的切片操做。
咱們都知道在C++當中有一個叫作next_permutation的函數,能夠傳入一個數組,返回下一個字典序的排列。在Python當中也有一樣的功能,可是是以迭代器的形式使用的。
舉個簡單的例子,好比咱們有a, b, c三個元素,咱們但願求出它的全部排列:
items = ['a', 'b', 'c']
from itertools import permutations
for p in permutations(items):
print(p)
複製代碼
permutations還支持多傳一個參數,好比上述的排列當中咱們但願只保留前兩個元素,除了切片以外,咱們只須要多傳一個參數就行了,like this:
for p in permutations(items, 2):
print(p)
複製代碼
除了排列以外,itertools當中還支持組合,用法仍是同樣,只是把函數名稱換成是combinations而已:
from itertools import combindations
for c in combinations(items):
print(c)
複製代碼
在通常的組合當中,一個元素一旦被選中那麼它接下來就會從候選集當中移除,不再會被選中。若是咱們但願得到有放回的組合,咱們能夠再換一個函數,這個函數名稱有點長,可是名字倒也直觀叫作combinations_with_replacement。但既然是有放回的抽樣,咱們須要設定元素的數量,不然抽樣能夠無限進行下去。
for c in combinations_with_replacement(items, 3):
print(c)
複製代碼
上一篇文章當中咱們介紹了zip能夠同時迭代多個迭代器,除此以外還有一種狀況是咱們須要把多個迭代器串起來迭代。好比系統的日誌打在了多個文件當中,咱們但願找出其中有error的日誌來分析。這個時候,咱們但願的不是同時讀取多個迭代器,而是但願可以有辦法將多個迭代器的內容串聯起來。這個功能就是itertools當中的chain方法,它接受多個迭代器,當咱們遍歷的時候,會自動將多個迭代器的內容串聯起來,咱們能夠無縫迭代。
舉個例子:
from itertools import chain
nums = [1, 2, 3]
chars = ['a', 'b', 'c']
for i in chain(nums, chars):
print(i)
複製代碼
這樣咱們會把nums和chars當中的內容一塊兒輸出出來,就好像從頭至尾只執行了一個迭代器同樣。
你可能會說咱們不用chain也能夠實現啊,咱們能夠這樣:
for i in nums + chars:
print(i)
複製代碼
的確,從結果上來看這樣也是行得通的。可是若是咱們分析一下內部執行的時候的中間變量,會發現當咱們執行nums+chars的時候,其實是先建立了一個新的臨時list。而後在這個list當中存儲nums和chars的數據,也就是說咱們迭代的實際上是這個新的list。這帶來的結果是咱們額外開闢了一段內存,而且花費了一些時間。若是咱們使用chain,它並不會有這樣的中間變量,徹底是經過迭代器來執行的迭代,很是節省內存,這也是chain的優勢。
對於歸併操做咱們應該都不陌生,在以前的歸併排序以及一些題解的文章當中咱們見過不少次。一樣,咱們在使用工具合併多個迭代器內容的時候,若是迭代器當中的內容有序,咱們也能夠對多個迭代器當中的元素進行歸併,而再也不須要咱們本身手動操做。
使用咱們以前介紹的heapq的庫能夠很是輕鬆地作到這一點,咱們一塊兒來看一個例子:
a = [1, 3, 5]
b = [2, 4, 6]
import heapq
for c in heapq.merge(a, b):
print(c)
複製代碼
執行以後,咱們會獲得[1, 2, 3, 4, 5, 6]的結果。也就是說經過heapq.merge操做,咱們把多個有序的迭代器合併到了一塊兒。固然咱們也能夠本身合併,但若是咱們只是須要利用當中的數據的話,使用merge操做能夠節省內存空間。
到這裏內容就結束了,本文和以前的文章基本上列舉完了經常使用的迭代器用法。固然,除了上述講到的內容以外,Python當中的迭代器還有一些其餘的用法,不過相對不太經常使用,感興趣的同窗能夠私下了解。
今天的文章就是這些,若是以爲有所收穫,請順手點個關注或者轉發吧,大家的舉手之勞對我來講很重要。