我們知道,迭代器的特點是:惰性求值(Lazy evaluation),即只有當迭代至某個值時,它才會被計算,這個特點使得迭代器特別適合於遍歷大檔案或無限集合等,因為我們不用一次性將它們儲存在記憶體中。
Python 內建的 itertools 模組包含了一系列用來產生不同型別迭代器的函式或類,這些函式的返回都是一個迭代器,我們可以通過 for 迴圈來遍歷取值,也可以使用 next()
來取值。
itertools 模組提供的迭代器函式有以下幾種型別:
- 無限迭代器:生成一個無限序列,比如自然數序列
1, 2, 3, 4, ...
; - 有限迭代器:接收一個或多個序列(sequence)作為引數,進行組合、分組和過濾等;
- 組合生成器:序列的排列、組合,求序列的笛卡兒積等;
無限迭代器
itertools 模組提供了三個函式(事實上,它們是類)用於生成一個無限序列迭代器:
- count(firstval=0, step=1)建立一個從 firstval (預設值為 0) 開始,以 step (預設值為 1) 為步長的的無限整數迭代器
- cycle(iterable)對 iterable 中的元素反覆執行迴圈,返回迭代器
- repeat(object [,times]反覆生成 object,如果給定 times,則重複次數為 times,否則為無限
下面,讓我們看看一些例子。
count
count()
接收兩個引數,第一個引數指定開始值,預設為 0,第二個引數指定步長,預設為 1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
>>> import itertools >>> >>> nums = itertools.count() >>> for i in nums: ... if i > 6: ... break ... print i ... 0 1 2 3 4 5 6 >>> nums = itertools.count(10, 2) # 指定開始值和步長 >>> for i in nums: ... if i > 20: ... break ... print i ... 10 12 14 16 18 20 |
cycle
cycle()
用於對 iterable 中的元素反覆執行迴圈:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
>>> import itertools >>> >>> cycle_strings = itertools.cycle('ABC') >>> i = 1 >>> for string in cycle_strings: ... if i == 10: ... break ... print i, string ... i += 1 ... 1 A 2 B 3 C 4 A 5 B 6 C 7 A 8 B 9 C |
repeat
repeat()
用於反覆生成一個 object:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
>>> import itertools >>> >>> for item in itertools.repeat('hello world', 3): ... print item ... hello world hello world hello world >>> >>> for item in itertools.repeat([1, 2, 3, 4], 3): ... print item ... [1, 2, 3, 4] [1, 2, 3, 4] [1, 2, 3, 4] |
有限迭代器
itertools 模組提供了多個函式(類),接收一個或多個迭代物件作為引數,對它們進行組合、分組和過濾等:
- chain()
- compress()
- dropwhile()
- groupby()
- ifilter()
- ifilterfalse()
- islice()
- imap()
- starmap()
- tee()
- takewhile()
- izip()
- izip_longest()
chain
chain
的使用形式如下:
1 |
chain(iterable1, iterable2, iterable3, ...) |
chain
接收多個可迭代物件作為引數,將它們『連線』起來,作為一個新的迭代器返回。
1 2 3 4 5 6 7 8 9 10 11 |
>>> from itertools import chain >>> >>> for item in chain([1, 2, 3], ['a', 'b', 'c']): ... print item ... 1 2 3 a b c |
chain
還有一個常見的用法:
1 |
chain.from_iterable(iterable) |
接收一個可迭代物件作為引數,返回一個迭代器:
1 2 3 4 5 |
>>> from itertools import chain >>> >>> string = chain.from_iterable('ABCD') >>> string.next() 'A' |
compress
compress
的使用形式如下:
1 |
compress(data, selectors) |
compress
可用於對資料進行篩選,當 selectors 的某個元素為 true 時,則保留 data 對應位置的元素,否則去除:
1 2 3 4 5 6 7 8 |
>>> from itertools import compress >>> >>> list(compress('ABCDEF', [1, 1, 0, 1, 0, 1])) ['A', 'B', 'D', 'F'] >>> list(compress('ABCDEF', [1, 1, 0, 1])) ['A', 'B', 'D'] >>> list(compress('ABCDEF', [True, False, True])) ['A', 'C'] |
dropwhile
dropwhile
的使用形式如下:
1 |
dropwhile(predicate, iterable) |
其中,predicate 是函式,iterable 是可迭代物件。對於 iterable 中的元素,如果 predicate(item) 為 true,則丟棄該元素,否則返回該項及所有後續項。
1 2 3 4 5 6 7 |
>>> from itertools import dropwhile >>> >>> list(dropwhile(lambda x: x < 5, [1, 3, 6, 2, 1])) [6, 2, 1] >>> >>> list(dropwhile(lambda x: x > 3, [2, 1, 6, 5, 4])) [2, 1, 6, 5, 4] |
groupby
groupby
用於對序列進行分組,它的使用形式如下:
1 |
groupby(iterable[, keyfunc]) |
其中,iterable 是一個可迭代物件,keyfunc 是分組函式,用於對 iterable 的連續項進行分組,如果不指定,則預設對 iterable 中的連續相同項進行分組,返回一個 (key, sub-iterator)
的迭代器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
>>> from itertools import groupby >>> >>> for key, value_iter in groupby('aaabbbaaccd'): ... print key, ':', list(value_iter) ... a : ['a', 'a', 'a'] b : ['b', 'b', 'b'] a : ['a', 'a'] c : ['c', 'c'] d : ['d'] >>> >>> data = ['a', 'bb', 'ccc', 'dd', 'eee', 'f'] >>> for key, value_iter in groupby(data, len): # 使用 len 函式作為分組函式 ... print key, ':', list(value_iter) ... 1 : ['a'] 2 : ['bb'] 3 : ['ccc'] 2 : ['dd'] 3 : ['eee'] 1 : ['f'] >>> >>> data = ['a', 'bb', 'cc', 'ddd', 'eee', 'f'] >>> for key, value_iter in groupby(data, len): ... print key, ':', list(value_iter) ... 1 : ['a'] 2 : ['bb', 'cc'] 3 : ['ddd', 'eee'] 1 : ['f'] |
ifilter
ifilter
的使用形式如下:
1 |
ifilter(function or None, sequence) |
將 iterable 中 function(item) 為 True 的元素組成一個迭代器返回,如果 function 是 None,則返回 iterable 中所有計算為 True 的項。
1 2 3 4 5 6 7 |
>>> from itertools import ifilter >>> >>> list(ifilter(lambda x: x < 6, range(10))) [0, 1, 2, 3, 4, 5] >>> >>> list(ifilter(None, [0, 1, 2, 0, 3, 4])) [1, 2, 3, 4] |
ifilterfalse
ifilterfalse
的使用形式和 ifilter
類似,它將 iterable 中 function(item) 為 False 的元素組成一個迭代器返回,如果 function 是 None,則返回 iterable 中所有計算為 False 的項。
1 2 3 4 5 6 7 |
>>> from itertools import ifilterfalse >>> >>> list(ifilterfalse(lambda x: x < 6, range(10))) [6, 7, 8, 9] >>> >>> list(ifilter(None, [0, 1, 2, 0, 3, 4])) [0, 0] |
islice
islice
是切片選擇,它的使用形式如下:
1 |
islice(iterable, [start,] stop [, step]) |
其中,iterable 是可迭代物件,start 是開始索引,stop 是結束索引,step 是步長,start 和 step 可選。
1 2 3 4 5 6 7 8 9 10 11 12 |
>>> from itertools import count, islice >>> >>> list(islice([10, 6, 2, 8, 1, 3, 9], 5)) [10, 6, 2, 8, 1] >>> >>> list(islice(count(), 6)) [0, 1, 2, 3, 4, 5] >>> >>> list(islice(count(), 3, 10)) [3, 4, 5, 6, 7, 8, 9] >>> list(islice(count(), 3, 10 ,2)) [3, 5, 7, 9] |
imap
imap
類似 map
操作,它的使用形式如下:
1 |
imap(func, iter1, iter2, iter3, ...) |
imap
返回一個迭代器,元素為 func(i1, i2, i3, ...)
,i1
,i2
等分別來源於 iter
, iter2
。
1 2 3 4 5 6 7 8 9 10 |
>>> from itertools import imap >>> >>> imap(str, [1, 2, 3, 4]) <itertools.imap object at 0x10556d050> >>> >>> list(imap(str, [1, 2, 3, 4])) ['1', '2', '3', '4'] >>> >>> list(imap(pow, [2, 3, 10], [4, 2, 3])) [16, 9, 1000] |
tee
tee
的使用形式如下:
1 |
tee(iterable [,n]) |
tee
用於從 iterable 建立 n 個獨立的迭代器,以元組的形式返回,n 的預設值是 2。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
>>> from itertools import tee >>> >>> tee('abcd') # n 預設為 2,建立兩個獨立的迭代器 (<itertools.tee object at 0x1049957e8>, <itertools.tee object at 0x104995878>) >>> >>> iter1, iter2 = tee('abcde') >>> list(iter1) ['a', 'b', 'c', 'd', 'e'] >>> list(iter2) ['a', 'b', 'c', 'd', 'e'] >>> >>> tee('abc', 3) # 建立三個獨立的迭代器 (<itertools.tee object at 0x104995998>, <itertools.tee object at 0x1049959e0>, <itertools.tee object at 0x104995a28>) |
takewhile
takewhile
的使用形式如下:
1 |
takewhile(predicate, iterable) |
其中,predicate 是函式,iterable 是可迭代物件。對於 iterable 中的元素,如果 predicate(item) 為 true,則保留該元素,只要 predicate(item) 為 false,則立即停止迭代。
1 2 3 4 5 6 |
>>> from itertools import takewhile >>> >>> list(takewhile(lambda x: x < 5, [1, 3, 6, 2, 1])) [1, 3] >>> list(takewhile(lambda x: x > 3, [2, 1, 6, 5, 4])) [] |
izip
izip
用於將多個可迭代物件對應位置的元素作為一個元組,將所有元組『組成』一個迭代器,並返回。它的使用形式如下:
1 |
izip(iter1, iter2, ..., iterN) |
如果某個可迭代物件不再生成值,則迭代停止。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
>>> from itertools import izip >>> >>> for item in izip('ABCD', 'xy'): ... print item ... ('A', 'x') ('B', 'y') >>> for item in izip([1, 2, 3], ['a', 'b', 'c', 'd', 'e']): ... print item ... (1, 'a') (2, 'b') (3, 'c') |
izip_longest
izip_longest
跟 izip
類似,但迭代過程會持續到所有可迭代物件的元素都被迭代完。它的形式如下:
1 |
izip_longest(iter1, iter2, ..., iterN, [fillvalue=None]) |
如果有指定 fillvalue,則會用其填充缺失的值,否則為 None。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
>>> from itertools import izip_longest >>> >>> for item in izip_longest('ABCD', 'xy'): ... print item ... ('A', 'x') ('B', 'y') ('C', None) ('D', None) >>> >>> for item in izip_longest('ABCD', 'xy', fillvalue='-'): ... print item ... ('A', 'x') ('B', 'y') ('C', '-') ('D', '-') |
組合生成器
itertools 模組還提供了多個組合生成器函式,用於求序列的排列、組合等:
- product
- permutations
- combinations
- combinations_with_replacement
product
product
用於求多個可迭代物件的笛卡爾積,它跟巢狀的 for 迴圈等價。它的一般使用形式如下:
1 |
product(iter1, iter2, ... iterN, [repeat=1]) |
其中,repeat 是一個關鍵字引數,用於指定重複生成序列的次數,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
>>> from itertools import product >>> >>> for item in product('ABCD', 'xy'): ... print item ... ('A', 'x') ('A', 'y') ('B', 'x') ('B', 'y') ('C', 'x') ('C', 'y') ('D', 'x') ('D', 'y') >>> >>> list(product('ab', range(3))) [('a', 0), ('a', 1), ('a', 2), ('b', 0), ('b', 1), ('b', 2)] >>> >>> list(product((0,1), (0,1), (0,1))) [(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1)] >>> >>> list(product('ABC', repeat=2)) [('A', 'A'), ('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'B'), ('B', 'C'), ('C', 'A'), ('C', 'B'), ('C', 'C')] >>> |
permutations
permutations
用於生成一個排列,它的一般使用形式如下:
1 |
permutations(iterable[, r]) |
其中,r 指定生成排列的元素的長度,如果不指定,則預設為可迭代物件的元素長度。
1 2 3 4 5 6 7 8 9 10 11 |
>>> from itertools import permutations >>> >>> permutations('ABC', 2) <itertools.permutations object at 0x1074d9c50> >>> >>> list(permutations('ABC', 2)) [('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'C'), ('C', 'A'), ('C', 'B')] >>> >>> list(permutations('ABC')) [('A', 'B', 'C'), ('A', 'C', 'B'), ('B', 'A', 'C'), ('B', 'C', 'A'), ('C', 'A', 'B'), ('C', 'B', 'A')] >>> |
combinations
combinations
用於求序列的組合,它的使用形式如下:
1 |
combinations(iterable, r) |
其中,r 指定生成組合的元素的長度。
1 2 3 4 |
>>> from itertools import combinations >>> >>> list(combinations('ABC', 2)) [('A', 'B'), ('A', 'C'), ('B', 'C')] |
combinations_with_replacement
combinations_with_replacement
和 combinations
類似,但它生成的組合包含自身元素。
1 2 3 4 |
>>> from itertools import combinations_with_replacement >>> >>> list(combinations_with_replacement('ABC', 2)) [('A', 'A'), ('A', 'B'), ('A', 'C'), ('B', 'B'), ('B', 'C'), ('C', 'C')] |
小結
- itertools 模組提供了很多用於產生多種型別迭代器的函式,它們的返回值不是 list,而是迭代器。