PyTips 0x16 - Python 迭代器工具

項目地址:https://git.io/pytipshtml

0x01 介紹了迭代器的概念,即定義了 __iter__()__next__() 方法的對象,或者經過 yield 簡化定義的「可迭代對象」,而在一些函數式編程語言(見 0x02 Python 中的函數式編程)中,相似的迭代器常被用於產生特定格式的列表(或序列),這時的迭代器更像是一種數據結構而非函數(固然在一些函數式編程語言中,這二者並沒有本質差別)。Python 借鑑了 APL, Haskell, and SML 中的某些迭代器的構造方法,並在 itertools 中實現(該模塊是經過 C 實現,源代碼:/Modules/itertoolsmodule.c)。python

itertools 模塊提供了以下三類迭代器構建工具:c++

  1. 無限迭代git

  2. 整合兩序列迭代github

  3. 組合生成器算法

1. 無限迭代

所謂無限(infinite)是指若是你經過 for...in... 的語法對其進行迭代,將陷入無限循環,包括:編程

  1. count(start, [step])segmentfault

  2. cycle(p)ruby

  3. repeat(elem [,n])數據結構

從名字大概能夠猜出它們的用法,既然說是無限迭代,咱們天然不會想要將其全部元素依次迭代取出,而一般是結合 map/zip 等方法,將其做爲一個取之不盡的數據倉庫,與有限長度的可迭代對象進行組合操做:

from itertools import cycle, count, repeat
print(count.__doc__)
count(start=0, step=1) --> count object

Return a count object whose .__next__() method returns consecutive values.
Equivalent to:

    def count(firstval=0, step=1):
        x = firstval
        while 1:
            yield x
            x += step
counter = count()
print(next(counter))
print(next(counter))
print(list(map(lambda x, y: x+y, range(10), counter)))

odd_counter = map(lambda x: 'Odd#{}'.format(x), count(1, 2))
print(next(odd_counter))
print(next(odd_counter))
0
1
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
Odd#1
Odd#3
print(cycle.__doc__)
cycle(iterable) --> cycle object

Return elements from the iterable until it is exhausted.
Then repeat the sequence indefinitely.
cyc = cycle(range(5))
print(list(zip(range(6), cyc)))
print(next(cyc))
print(next(cyc))
[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 0)]
1
2
print(repeat.__doc__)
repeat(object [,times]) -> create an iterator which returns the object
for the specified number of times.  If not specified, returns the object
endlessly.
print(list(repeat('Py', 3)))
rep = repeat('p')
print(list(zip(rep, 'y'*3)))
['Py', 'Py', 'Py']
[('p', 'y'), ('p', 'y'), ('p', 'y')]

2. 整合兩序列迭代

所謂整合兩序列,是指以兩個有限序列爲輸入,將其整合操做以後返回爲一個迭代器,最爲常見的 zip 函數就屬於這一類別,只不過 zip 是內置函數。這一類別完整的方法包括:

  1. accumulate()

  2. chain()/chain.from_iterable()

  3. compress()

  4. dropwhile()/filterfalse()/takewhile()

  5. groupby()

  6. islice()

  7. starmap()

  8. tee()

  9. zip_longest()

這裏就不對全部的方法一一舉例說明了,若是想要知道某個方法的用法,基本經過 print(method.__doc__) 就能夠了解,畢竟 itertools 模塊只是提供了一種快捷方式,並無隱含什麼深奧的算法。這裏只對下面幾個我以爲比較有趣的方法進行舉例說明。

from itertools import cycle, compress, islice, takewhile, count

# 這三個方法(若是使用恰當)能夠限定無限迭代
# print(compress.__doc__)
print(list(compress(cycle('PY'), [1, 0, 1, 0])))

# 像操做列表 l[start:stop:step] 同樣操做其它序列
# print(islice.__doc__)
print(list(islice(cycle('PY'), 0, 2)))

# 限制版的 filter
# print(takewhile.__doc__)
print(list(takewhile(lambda x: x < 5, count())))
['P', 'P']
['P', 'Y']
[0, 1, 2, 3, 4]
from itertools import groupby
from operator import itemgetter
print(groupby.__doc__)

for k, g in groupby('AABBC'):
    print(k, list(g))
db = [dict(name='python', script=True),
      dict(name='c', script=False),
      dict(name='c++', script=False),
      dict(name='ruby', script=True)]
keyfunc = itemgetter('script')

db2 = sorted(db, key=keyfunc) # sorted by `script'
for isScript, langs in groupby(db2, keyfunc):
    print(', '.join(map(itemgetter('name'), langs)))
groupby(iterable[, keyfunc]) -> create an iterator which returns
(key, sub-iterator) grouped by each value of key(value).

A ['A', 'A']
B ['B', 'B']
C ['C']
c, c++
python, ruby
from itertools import zip_longest

# 內置函數 zip 以較短序列爲基準進行合併,
# zip_longest 則以最長序列爲基準,並提供補足參數 fillvalue
# Python 2.7 中名爲 izip_longest

print(list(zip_longest('ABCD', '123', fillvalue=0)))
[('A', '1'), ('B', '2'), ('C', '3'), ('D', 0)]

3. 組合生成器

關於生成器的排列組合:

  1. product(*iterables, repeat=1):兩輸入序列的笛卡爾乘積

  2. permutations(iterable, r=None):對輸入序列的徹底排列組合

  3. combinations(iterable, r):有序版的排列組合

  4. combinations_with_replacement(iterable, r):有序版的笛卡爾乘積

from itertools import product, permutations, combinations, combinations_with_replacement
print(list(product(range(2), range(2))))
print(list(product('AB', repeat=2)))
[(0, 0), (0, 1), (1, 0), (1, 1)]
[('A', 'A'), ('A', 'B'), ('B', 'A'), ('B', 'B')]
print(list(combinations_with_replacement('AB', 2)))
[('A', 'A'), ('A', 'B'), ('B', 'B')]
# 賽馬問題:4匹馬前2名的排列組合(A^4_2)
print(list(permutations('ABCDE', 2)))
[('A', 'B'), ('A', 'C'), ('A', 'D'), ('A', 'E'), ('B', 'A'), ('B', 'C'), ('B', 'D'), ('B', 'E'), ('C', 'A'), ('C', 'B'), ('C', 'D'), ('C', 'E'), ('D', 'A'), ('D', 'B'), ('D', 'C'), ('D', 'E'), ('E', 'A'), ('E', 'B'), ('E', 'C'), ('E', 'D')]
# 綵球問題:4種顏色的球任意抽出2個的顏色組合(C^4_2)
print(list(combinations('ABCD', 2)))
[('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'C'), ('B', 'D'), ('C', 'D')]

總結

迭代器工具在產生數據的時候將會顯得很是便捷、高效,掌握了這些基本的方法以後,經過簡單的組合就能夠得到更多迭代器工具。


歡迎關注公衆號 PyHub 每日推送

pyhub

相關文章
相關標籤/搜索