文章目錄
- 一、合并和分解迭代器
- 1、chain:首尾相接
- 2、zip / zip_longest:對齊取數
- 3、islice:切片
- 4、tee:分裂
- 二、轉換輸入
- 1、map / starmap:函數映射
- 三、生成新值
- 1、count:生成連續整數
- 2、repeat:單個值的重復
- 3、cycle:某段內容的循環重復
- 四、過濾
- 1、takewhile:獲取元素直至 False
- 2、dropwhile:跳過元素直至 False
- 3、filter / filterfalse:篩選每個元素
- 4、compress:迭代器控制元素輸出
- 五、數據分組
- 1、groupby:對連續相同元素分組
- 六、合并輸入
- 1、accumulate:元素累加
- 2、product:笛卡爾積
- 3、permutations:元素有序排列,M個元素中選N個
- 4、combinations:元素無序組合,M個元素中選N個
- 5、combinations_with_replacement:考慮自身元素的無序組合
itertools
模塊包括一組用于處理序列數據集的函數。該模塊的目的是能夠快速處理數據、高效使用內存,以及表述更加復雜的迭代算法。
import itertools
一、合并和分解迭代器
1、chain:首尾相接
chain
可以把多個源迭代器從頭到尾連接成一個迭代器:
it = itertools.chain(iter([1, 2, 3]), ['a', 'b', 'c'])
>>> list(it): [1, 2, 3, 'a', 'b', 'c']
chain.from_iterable()
方法適用于無法提前知道源迭代器數據,或者需要采用懶方式計算的情況。注意,該方法只能傳入一個參數:
def make_iterables_to_chain():yield [1, 2, 3]yield ['a', 'b', 'c']it = itertools.chain.from_iterable(make_iterables_to_chain())
>>> list(it): [1, 2, 3, 'a', 'b', 'c']
2、zip / zip_longest:對齊取數
Python 內置的zip
函數可以把多個源迭代器封裝成惰性生成器(lazy generator),每次推進時會從這些源迭代器中分別獲取下一個元素值,形成元組返回:
it = zip([1, 2, 3], ['a', 'b', 'c'])
>>> list(it): [(1, 'a'), (2, 'b'), (3, 'c')]
任何一個源迭代器耗盡,zip
就會停止,也就是說,zip
惰性生成器的可迭代次數,取決于最短源迭代器的可迭代次數。
itertools
模塊中的zip_longest
函數會將所有的源迭代器耗盡,即使它們的可迭代次數不同。默認會把源迭代器缺少的值替換為None
,可以借助參數fillvalue
來指定缺失值的替換值:
it = itertools.zip_longest([1, 2, 3, 4], ['a', 'b', 'c'], fillvalue='missing_value')
>>> list(it): [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'missing_value')]
3、islice:切片
islice
在不拷貝數據的前提下,按照下標切割源迭代器。與列表相同,islice
同樣包括開始位置start
、結束位置end
和步長step
,其中start
和step
是可選的。
# 僅配置結束位置
it = itertools.islice([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 5)
>>> list(it): [0, 1, 2, 3, 4]# 配置開始位置、結束位置和步長
it = itertools.islice(range(100), 5, 15, 2)
>>> list(it): [5, 7, 9, 11, 13]
4、tee:分裂
tee
函數可以將源迭代器分裂成多個獨立的迭代器,分裂個數由第二個參數指定(默認為2)。如果分裂出的迭代器推進速度不一致,程序可能要用大量內存做緩沖,以存放進度落后的迭代器將來會用到的元素。
ori_it = [1, 2, 3, 4, 5]
it1, it2, it3 = itertools.tee(ori_it, 3)
>>> list(it1/it2/it3): [1, 2, 3, 4, 5]
即使用tee
函數創建出了新迭代器,如果源迭代器被推進,新迭代器將不會再產出被推進的值。所以創建了新迭代器后,不建議再使用源迭代器。
ori_it = iter([1, 2, 3, 4, 5])
it1, it2, it3 = itertools.tee(ori_it, 3)
next(ori_it), next(ori_it)
>>> list(it1/it2/it3): [3, 4, 5]
二、轉換輸入
1、map / starmap:函數映射
Python 內置的map
函數能夠將源迭代器中的值作為參數,調用映射函數并返回一個迭代器。任何一個源迭代器被耗盡時,map
函數都會停止。
list1 = [1, 2, 3, 4, 5]
list2 = [0, 2, 4]result1 = map(lambda x: x**2, list1)
>>> list(result1): [1, 4, 9, 16, 25]def map_multiple(x, y):return x*y
result2 = map(map_multiple, list1, list2)
>>> list(result2): [0, 4, 12]
itertools
模塊中的starmap
函數與map
函數類似,但是它是使用*
(unpacking)語法分解單個源迭代器中的元素作為映射函數的參數:
values = [(0, 5), (1, 6), (2, 7), (3, 8), (4, 9)]
it = itertools.starmap(lambda x, y: x*y, values)
>>> list(result1): [0, 6, 14, 24, 36]
可以通俗認為,傳入map
函數的映射函數名為f(it1, it2)
,而傳入starmap
函數的映射函數名為f(*it)
。
三、生成新值
1、count:生成連續整數
count
函數能夠無限地生成連續的整數,首個生成的整數可以通過第一個參數指定(默認為0)。count
函數可以指定「開始位置」和「步長」參數,但是沒有「結束位置」參數。
it = zip(itertools.count(), ['a', 'b', 'c'])
>>> list(it): [(0, 'a'), (1, 'b'), (2, 'c')]# -1 為起始整數,3 為步長
it = zip(itertools.count(-1, 3), ['a', 'b', 'c'])
>>> list(it): [(-1, 'a'), (2, 'b'), (5, 'c')]
2、repeat:單個值的重復
repeat
函數可以不停地輸出某個值,允許配置第二個參數times
來限制輸出次數:
it = itertools.repeat('hello', 5)
>>> list(it): ['hello', 'hello', 'hello', 'hello', 'hello']
3、cycle:某段內容的循環重復
cycle
函數可以循環地重復輸出源迭代器中的各項元素。由于必須記住源迭代器的全部內容,所以如果源迭代器很長,可能會耗費大量內存。
it = zip(range(7), itertools.cycle(['a', 'b', 'c']))
>>> list(it): [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'a'), (4, 'b'), (5, 'c'), (6, 'a')]
四、過濾
1、takewhile:獲取元素直至 False
takewhile
函數會一直從源迭代器中獲取元素,直至判斷函數返回False
,停止輸出該元素,也不會再判斷后續元素:
it = itertools.takewhile(lambda x: x < 2, [-1, 0, 1, 2, -2])
>>> list(it): [-1, 0, 1]
2、dropwhile:跳過元素直至 False
與takewhile
函數相反,dropwhile
函數會一直跳過源迭代器中的元素,直至判斷函數返回False
,開始輸出該元素及后續元素(后續不再判斷):
it = itertools.dropwhile(lambda x: x < 2, [-1, 0, 1, 2, -2])
>>> list(it): [2, -2]
3、filter / filterfalse:篩選每個元素
Python 內置的filter
函數能夠從源迭代器中篩選出判斷函數返回True
的元素,并返回一個迭代器。filter
函數會測試每一個元素。
it = filter(lambda x: x%2 == 0, [1, 2, 3, 4, 5])
>>> list(it): [2, 4]
itertools
模塊中的filterfalse
函數恰好與filter
函數相反,從源迭代器中篩選出判斷函數返回False
的元素。同樣,filterfalse
函數會測試每一個元素。
it = itertools.filterfalse(lambda x: x%2 == 0, [1, 2, 3, 4, 5])
>>> list(it): [1, 3, 5]
4、compress:迭代器控制元素輸出
compress
函數使用第二個源迭代器的布爾元素來判斷,對第一個源迭代器的元素是輸出還是跳過。兩個迭代器中的任何一個被耗盡,都會停止輸出。
it = itertools.compress(range(1, 10), [True, False, False, True, False])
>>> list(it): [1, 4]
五、數據分組
1、groupby:對連續相同元素分組
groupby
函數用于對源迭代器中連續相同的元素進行分組,生成的迭代器每次生成一個(key, group)
對,key
是分組的鍵值,group
是一個子迭代器,包含當前組的所有元素。
for key, group in itertools.groupby('AAAABBBCCD'):print(key, list(group))
>>> 輸出結果:A ['A', 'A', 'A', 'A']B ['B', 'B', 'B']C ['C', 'C']D ['D']for key, group in itertools.groupby([('a', 1), ('a', 2), ('b', 3), ('b', 4), ('c', 5)], lambda x: x[0]):print(key, list(group))
>>> 輸出結果:a [('a', 1), ('a', 2)]b [('b', 3), ('b', 4)]c [('c', 5)]
請注意,如果相同的元素不連續,會被分到不同的組。因此,如果要將所有相同的元素分組而不管是否連續,通常需要先對數據進行排序。
for key, group in itertools.groupby([1, 2, 2, 3, 4, 4, 4, 1, 1, 3]):print(key, list(group))
>>> 輸出結果:1 [1]2 [2, 2]3 [3]4 [4, 4, 4]1 [1, 1]3 [3]
六、合并輸入
1、accumulate:元素累加
accumulate
函數會對源迭代器中的元素進行累加,每次累加都會生成一個元素。可以指定表示累加邏輯的函數,該函數可以是任何的雙參數函數,默認邏輯是兩值相加。
it1 = itertools.accumulate(range(5))
>>> list(it1): [0, 1, 3, 6, 10]it2 = itertools.accumulate('abcde')
>>> list(it2): ['a', 'ab', 'abc', 'abcd', 'abcde']it = itertools.accumulate('abcde', lambda x, y: y + x + y)
>>> list(it): ['a', 'bab', 'cbabc', 'dcbabcd', 'edcbabcde']
accumulate
函數和functools
模塊里的reduce
函數類似,但是后者只會給出最終的累計值:
import functools
# result 等于 45
result = functools.reduce(lambda x, y: x + y, range(10))
2、product:笛卡爾積
product
函數從一個或者多個源迭代器中獲取元素,并計算笛卡爾積。它可以取代多層嵌套的for
循環。要計算源迭代器與自身的積,可以使用參數repeat
指定輸入重復多少次。
single = itertools.product([1, 2], repeat=2)
>>> list(single): [(1, 1), (1, 2), (2, 1), (2, 2)]multiple = itertools.product([1, 2], ['a', 'c'])
>>> list(multiple): [(1, 'a'), (1, 'c'), (2, 'a'), (2, 'c')]
3、permutations:元素有序排列,M個元素中選N個
permutations
函數將源迭代器中的元素以指定長度進行有序排列,默認(不指定長度)會生成所有排列的全集(長度為源迭代器中元素個數)。使用r
參數指定所返回排列的長度。
it1 = itertools.permutations('abc')
>>> list(it1): [('a', 'b', 'c'), ('a', 'c', 'b'), ('b', 'a', 'c'), ('b', 'c', 'a'), ('c', 'a', 'b'), ('c', 'b', 'a')]it2 = itertools.permutations('abc', r=2)
>>> list(it2): [('a', 'b'), ('a', 'c'), ('b', 'a'), ('b', 'c'), ('c', 'a'), ('c', 'b')]
4、combinations:元素無序組合,M個元素中選N個
combinations
函數將源迭代器中的元素以指定長度進行無序組合。與permutations
函數不同的是,該函數的 r 參數是必要參數。只要源迭代器的元素取值是唯一的,輸出就不會包含任何重復的值。
it = itertools.combinations('abca', r=2)
>>> list(it): [('a', 'b'), ('a', 'c'), ('a', 'a'), ('b', 'c'), ('b', 'a'), ('c', 'a')]
5、combinations_with_replacement:考慮自身元素的無序組合
與combinations
函數不同的是,combinations_with_replacement
函數會將當前元素與「當前元素、所有的其他元素」均進行配對:
it = itertools.combinations_with_replacement('abcd', r=2)
>>> list(it): [('a', 'a'), ('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'b'), ('b', 'c'), ('b', 'd'), ('c', 'c'), ('c', 'd'), ('d', 'd')]