Python 迭代器工具包【推荐】
原文:https://git.io/pytips
0x01介绍了迭代器的概念,即定义了__iter__()和__next__()方法的对象,或者通过yield简化定义的“可迭代对象”,而在一些函数式编程语言(见0x02Python中的函数式编程)中,类似的迭代器常被用于产生特定格式的列表(或序列),这时的迭代器更像是一种数据结构而非函数(当然在一些函数式编程语言中,这两者并无本质差异)。Python借鉴了APL,Haskell,andSML中的某些迭代器的构造方法,并在itertools中实现(该模块是通过C实现,源代码:/Modules/itertoolsmodule.c)。
itertools模块提供了如下三类迭代器构建工具:
无限迭代
整合两序列迭代
组合生成器
1.无限迭代
所谓无限(infinite)是指如果你通过for...in...的语法对其进行迭代,将陷入无限循环,包括:
count(start,[step]) cycle(p) repeat(elem[,n])
从名字大概可以猜出它们的用法,既然说是无限迭代,我们自然不会想要将其所有元素依次迭代取出,而通常是结合map/zip等方法,将其作为一个取之不尽的数据仓库,与有限长度的可迭代对象进行组合操作:
fromitertoolsimportcycle,count,repeat
print(count.__doc__)
count(start=0,step=1)-->countobject
Returnacountobjectwhose.__next__()methodreturnsconsecutivevalues.
Equivalentto:
defcount(firstval=0,step=1):
x=firstval
while1:
yieldx
x+=step
counter=count()
print(next(counter))
print(next(counter))
print(list(map(lambdax,y:x+y,range(10),counter)))
odd_counter=map(lambdax:'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)-->cycleobject
Returnelementsfromtheiterableuntilitisexhausted.
Thenrepeatthesequenceindefinitely.
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])->createaniteratorwhichreturnstheobject
forthespecifiednumberoftimes.Ifnotspecified,returnstheobject
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是内置函数。这一类别完整的方法包括:
accumulate() chain()/chain.from_iterable() compress() dropwhile()/filterfalse()/takewhile() groupby() islice() starmap() tee() zip_longest()
这里就不对所有的方法一一举例说明了,如果想要知道某个方法的用法,基本通过print(method.__doc__)就可以了解,毕竟itertools模块只是提供了一种快捷方式,并没有隐含什么深奥的算法。这里只对下面几个我觉得比较有趣的方法进行举例说明。
fromitertoolsimportcycle,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(lambdax:x<5,count())))
['P','P']
['P','Y']
[0,1,2,3,4]
fromitertoolsimportgroupby
fromoperatorimportitemgetter
print(groupby.__doc__)
fork,gingroupby('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)#sortedby`script'
forisScript,langsingroupby(db2,keyfunc):
print(','.join(map(itemgetter('name'),langs)))
groupby(iterable[,keyfunc])->createaniteratorwhichreturns
(key,sub-iterator)groupedbyeachvalueofkey(value).
A['A','A']
B['B','B']
C['C']
c,c++
python,ruby
fromitertoolsimportzip_longest
#内置函数zip以较短序列为基准进行合并,
#zip_longest则以最长序列为基准,并提供补足参数fillvalue
#Python2.7中名为izip_longest
print(list(zip_longest('ABCD','123',fillvalue=0)))
[('A','1'),('B','2'),('C','3'),('D',0)]
3.组合生成器
关于生成器的排列组合:
product(*iterables,repeat=1):两输入序列的笛卡尔乘积
permutations(iterable,r=None):对输入序列的完全排列组合
combinations(iterable,r):有序版的排列组合
combinations_with_replacement(iterable,r):有序版的笛卡尔乘积
fromitertoolsimportproduct,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')]