首頁 > 軟體

Python中的高效迭代庫itertools,排列組合隨便求

2021-05-21 18:30:07

來源:AI入門學習

作者:小伍哥

本文目錄

一、模組概述

二、組合生成器

2.1 product

2.2 permutations

2.3 combinations

2.4 combinations_with_replacement

三、無限迭代器

3.1 count

3.2 cycle

3.3 repeat

四、有限迭代器

4.1 accumulate

4.2 chain

4.3 chain.from_iterable

4.4 compress

4.5 dropwhile

4.6 filterfalse

4.7 groupby

4.8 islice

4.9 starmap

4.10 takewhile

4.11 tee

4.12 zip_longest

五、總結

一、模組概述

Functional tools for creating and using iterators,為高效迴圈而創建迭代器的函數。本模組標準化了一個快速、高效利用記憶體的核心工具集,這些工具本身或組合都很有用。它們一起形成了「迭代器代數」,這使得在純Python中有可能創建簡潔又高效的專用工具。

permutations函數可以求序列的排列,combinations函數可以求序列的組合除了這兩個函數外,itertools還有相當多的功能,它主要是提供迭代類的操作。

迭代器的特點是:惰性求值(Lazy evaluation),即只有當迭代至某個值時,它才會被計算,這個特點使得迭代器特別適合於遍歷大檔案或無限集合等,因為我們不用一次性將它們儲存在記憶體中。itertools 模組提供的迭代器函數有以下幾種類型:

組合生成器:序列的排列、組合,求序列的笛卡兒積等,比如product可以生成兩個序列的笛卡爾積;

無限迭代器:生成一個無限序列,比如count函數能生成自然數序列 1, 2, 3, 4, ...

有限迭代器:接收一個或多個序列(sequence)作為參數,進行組合、分組和過濾等,比如chain函數,能組合多個序列

print(dir(itertools))['__doc__', '__loader__', '__name__', '__package__', '__spec__', '_grouper', '_tee', '_tee_dataobject', 'accumulate', 'chain', 'combinations', 'combinations_with_replacement', 'compress', 'count', 'cycle', 'dropwhile', 'filterfalse', 'groupby', 'islice', 'permutations', 'product', 'repeat', 'starmap', 'takewhile', 'tee', 'zip_longest']

總之該模組為Python為創建自定義迭代器提供了非常好用的模組——itertools。由itertools提供的工具通常都很快速而且節省記憶體。你可以利用這些組成部分去創建自己獨有的迭代器以完成高效的迴圈

官方參考文件:https://docs.python.org/zh-cn/3/library/itertools.html

二、排列組合迭代器

2.1 product

作用:用於求多個可迭代物件的笛卡爾積,它跟巢狀的 for 迴圈等價

語法:itertools.product(iter1, iter2, ... iterN, [repeat=1])

foreachinitertools.product('ABCD', 'XY'): print(each)('A', 'X')('A', 'Y')('B', 'X')('B', 'Y')('C', 'X')('C', 'Y')('D', 'X')('D', 'Y')foreachinitertools.product('abc', repeat=2): print (each)('a', 'a')('a', 'b')('a', 'c')('b', 'a')('b', 'b')('b', 'c')('c', 'a')('c', 'b')('c', 'c')

2.2 permutations

作用:返回長度為r的排列

語法:itertools.permutations(iteravle[,r])

iterable: 可迭代物件r: 關鍵字參數, 新元素的長度, 預設為 None, 即為新元素的長度就是元素個數將 iterable 中的元素以長度為 r 進行排列。每個排列組合生成一個元組並新增到新迭代器中。排列時,排列順序是按照 iterable 中元素的順序進行的。因此,未排序的 iterable 和已排序的 iterable 排列後的結果是不同的。

若 iterable 中有相同值的元素,但是它們的位置是不同的,排列時也就會會認為它們是不同的。注意:排列即為數學上的排列,從 n 個元素中取出 m 個元素的無重複排列或直線排列。

foreachinitertools.permutations('abc', 2): print (each)('a', 'b')('a', 'c')('b', 'a')('b', 'c')('c', 'a')('c', 'b')

2.3 combinations

作用:返回指定長度的組合

語法:itertools.combinations(iterable, r)

iterable: 可迭代物件r: 新元素的長度for each in itertools.combinations('abc', 2): print (each)('a', 'b')('a', 'c')('b', 'c')將 iterable 中的元素以長度為 r 進行組合。每個排列組合生成一個元組並新增到新迭代器中。與 permutations() 函數基本一致,但是 combinations() 函數會過濾掉元素值一致的元組。'''相比於排列,組合會篩選掉元素值一樣的元組'''list(itertools.combinations('ABC', 2))[('A', 'B'), ('A', 'C'), ('B', 'C')]'''排列對照組'''list(itertools.permutations('ABC', 2))[('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'C'), ('C', 'A'), ('C', 'B')]

2.4 combinations_with_replacement

作用:返回指定長度的組合,組合內元素可重複

語法:itertools.combinations_with_replacement(iterable, r)

iterable: 可迭代物件r: 關鍵字參數, 新元素的長度, 預設為 None, 即為新元素的長度就是元素個數foreachinitertools.combinations_with_replacement('abc', 2): print (each)('a', 'a')('a', 'b')('a', 'c')('b', 'b')('b', 'c')('c', 'c')

三、無限迭代器

有三個無限迭代器,當你使用它們的時候,你要知道何時去跳出這個迴圈,不然你將陷入無限迴圈之中,在生產數字或者遍歷事先不知道長度的資料時非常有用。

3.1 count()

作用:返回以start開始,step遞增的序列,無限遞增

語法:itertools.count(start=0,step=1)

for each in itertools.count(start=0, step=2): print (each)12...100003'''小應用, 當取到第三個 A 時停止'''test_str = ''for i in itertools.cycle('ABC'): test_str += i if test_str.count('A') >= 3: breakprint(test_str)# ABCABCA

3.2 cycle()

作用:將迭代器進行無限迭代

語法:itertools.cycle(iterable)

foreach in itertools.cycle('ab'): print(each)ab...ba

3.3 repeat()

作用:不停的返回object物件,如果指定了times,則返回times次

語法:itertools.repeat(object,[,times])

foreach in itertools.repeat('ab', 2):print(each)abab

四、有限迭代器

4.1 accumulate()

作用:創建一個迭代器,返回累積彙總值或其他雙目運算函數的累積結果值(通過可選的 func 參數指定),,若傳入 func,則按照 func 中的方法執行。

語法:itertools.accumulate(iterable[, func, *, initial=None])

iterable: 可迭代物件func: 帶有兩個參數的函數, 可選參數,func 參數有幾種用法。它可以被設為 min() 最終得到一個最小值,或者設為 max() 最終得到一個最大值,或設為 operator.mul() 最終得到一個乘積。攤銷表可通過累加利息和支付款項得到。給iterable設定初始值並只將參數 func 設為累加總數可以對一階 遞迴關係 建模。initial: 關鍵字參數, 預設為 None, 若此參數傳參, 則此參數作為 iterable 的第一個元素'''預設情況, 返回累計彙總值'''list(itertools.accumulate([1, 2, 3, 4, 5]))[1, 3, 6, 10, 15]'''方法修改為計算累計的乘積'''import operator #該模組輸出一系列對應Python內部操作符的函數data = [3, 4, 6, 2, 1, 9, 0, 7, 5, 8]list(itertools.accumulate(data, operator.mul)) [3, 12, 72, 144, 144, 1296, 0, 0, 0, 0]'''方法修改為計算累計的最大值'''list(itertools.accumulate(data, max))[3, 4, 6, 6, 6, 9, 9, 9, 9, 9] # Amortize a 5% loan of 1000 with 4 annual payments of 90cashflows = [1000, -90, -90, -90, -90]list(itertools.accumulate(cashflows, lambda bal, pmt: bal*1.05 + pmt))[1000, 960.0, 918.0, 873.9000000000001, 827.5950000000001]#Chaotic recurrence relation #https://en.wikipedia.org/wiki/Logistic_maplogistic_map = lambda x, _: r * x * (1 - x)r = 3.8x0 = 0.4inputs = repeat(x0, 36) # only the initial value is used[format(x, '.2f') for x in accumulate(inputs, logistic_map)]['0.40', '0.91', '0.30', '0.81', '0.60', '0.92', '0.29', '0.79', '0.63', '0.88', '0.39', '0.90', '0.33', '0.84', '0.52', '0.95', '0.18', '0.57', '0.93', '0.25', '0.71', '0.79', '0.63', '0.88', '0.39', '0.91', '0.32', '0.83', '0.54', '0.95', '0.20', '0.60', '0.91', '0.30', '0.80', '0.60']'''在迭代器起始位置新增一個元素, 方法不變, 返回累計彙總值'''list(itertools.accumulate([1, 2, 3, 4, 5], initial=100))# [100, 101, 103, 106, 110, 115]'''在迭代器起始位置新增一個元素, 方法修改為計算累計的乘積'''list(itertools.accumulate([1, 2, 3, 4, 5], lambda x, y: x * y, initial=10))#[10, 10, 20, 60, 240, 1200]

4.2 chain()

作用:chain 接收多個可迭代物件作為參數,將它們『連線』起來,作為一個新的迭代器返回。

語法:chain(iterable1, iterable2, iterable3, ...)

list(itertools.chain([1, 2, 3], ('A', 'B', 'C'), {'一', '二', '三'}))[1, 2, 3, 'A', 'B', 'C', '二', '一', '三']list(itertools.chain( 'ABC', 'DEF'))['A', 'B', 'C', 'D', 'E', 'F']

4.3 chain.from_iterable

作用:與 itertools.chain() 函數類似,但是參數是一個可迭代物件,將這個可迭代物件中元素一一新增到新迭代器中,如果元素是一個可迭代物件,那麼會將這個元素內的元素一一新增到新迭代器中。小編自己的理解就是迭代器降維。

語法:itertools.chain.from_iterable(iterable)

'''將二維迭代器降維'''temp = itertools.chain.from_iterable(['1', ['2', '3'], ('4', '5')])print(list(temp))# ['1', '2', '3', '4', '5']'''只能降一層維度, 三維將至二維'''temp = itertools.chain.from_iterable(['1', ['2', '3'], ('4', ['5', '6'])])print(list(temp))# ['1', '2', '3', '4', ['5', '6']]

PS: 迭代器維度概念可以理解為,整個迭代器中的元素都不是迭代器類型的就是一維,迭代器中的元素有是迭代器的就是二維,迭代器中的元素有是迭代器的,然後這個迭代器中還有元素是迭代器的就是三維,依此類推。

4.4 compress

作用:創建一個迭代器,將 data 中經過 selectors 真值測試為 True 的元素保留。當兩個可迭代物件中的某一個到達末尾時執行停止,返回最終結果。

語法:compress(data, selectors)

data: 可迭代物件, 包含所需的資料selectors: 可迭代物件, 真值測試資料for each in itertools.compress('abcd', [1, 0, 1, 0]): print (each)ac'''只判斷前三個元素, 並且索引值為 0 和 2 的元素會保留到新迭代器中並返回'''temp = itertools.compress(['A', 'B', 'C', 'D'], [1, 0, 1])list(temp)# ['A', 'C']

4.5 dropwhile

作用:直到predicate為真,就返回iterable剩下的資料, 否則drop掉

語法:itertools.dropwhile(predicate, iterable)

foreachinitertools.dropwhile(lambdax:x<5,[2,1,6,8,2,1]):print(each)6821

4.6 filterfalse

作用:創建一個迭代器,僅保留 iterable 中在 predicate 計算中為 False 的元素。如果 predicate 傳入的是 None,則相當於傳入 bool,意思是做真值測試。

語法:itertools.filterfalse(predicate, iterable)

predicate: 只需要一個參數的函數iterable: 可迭代物件'''元素的值減2小於等於0的為True'''temp = itertools.filterfalse(lambda x: x - 2 <= 0, [1, 2, 0, 3, 1])print(list(temp))# [3]'''真值測試'''temp = itertools.filterfalse(None, [1, 2, 0, 3, 1])print(list(temp))# [0]

4.7 groupby

作用:返回一組(key,itera),key為iterable的值,itera為等於key的所有項

語法:itertools.groupby(iterable[,key])

for key, vale in itertools.groupby('aabbbc'): print( key, list(vale))a ['a', 'a']b ['b', 'b', 'b']c ['c']

4.8 islice

作用:相當於迭代器方式的切片操作

語法:itertools.islice(iterable, start,stop[,step])

foreach in itertools.islice('abcdefg', 1, 4, 2): print(each) bd

4.9 starmap()

作用:返回function(iter)的值,iter為iterable的元素

語法:itertools.starmap(function,iterable)

foreachinitertools.starmap(lambdax,y:x*y,[(1,2),(3,4)]):print(each)212

4.10 takewhile()

作用:創建一個迭代器,將 iterable 中的元素當作 function 的參數計算,與 dropwhile() 函數恰恰相反,當結果的布爾值為 True 時,其元素新增到新迭代器中, 直到有元素的計算結果為 False 時,此元素與之後的元素全部拋棄。

語法:itertools.takewhile(predicate,iterable)

foreachinitertools.takewhile(lambdax:x<5,[1,3,5,6]):print(each)13

4.11 tee

作用:從一個可迭代物件中分裂出 n 個獨立的可迭代物件並返回。

語法:itertools.tee(iterable, n=2)

foriinitertools.tee([1,2,3,4,5,6],2):print(list(i))# [1, 2, 3, 4, 5, 6]# [1, 2, 3, 4, 5, 6]

4.12 zip_longest

作用:創建一個迭代器,從所有傳入的可迭代物件中抽取一個元素,將它們組合成一個元組,然後新增到迭代器中。

語法:itertools.zip_longest(*iterables, fillvalue=None)

iterables: 一個或多個可迭代物件fillvalue: 關鍵字參數, 填充值, 預設為 Nonelist(itertools.zip_longest('xyz', '123456', '小伍哥', fillvalue='*'))[('x', '1', '小'), ('y', '2', '伍'), ('z', '3', '哥'), ('*', '4', '*'), ('*', '5', '*'), ('*', '6', '*')]

五、總 結

迭代器(生成器)在Python中是一種很常用也很好用的資料結構,比起列表(list)來說,迭代器最大的優勢就是延遲計算,按需使用,從而提高開發體驗和運行效率,以至於在Python 3中map,filter等操作返回的不再是列表而是迭代器。而通過iter函數把列表物件轉化為迭代器物件又有點多此一舉,這時候我們今天的主角itertools就該上場了。

itertools中的函數大多是返回各種迭代器物件,其中很多函數的作用我們平時要寫很多程式碼才能達到,而在運行效率上反而更低,大概就總結到這裡,不過Python的各種語言特性和庫還是要多用才能熟練,最終達到隨手拈來的程度。


IT145.com E-mail:sddin#qq.com