itertools提供的工具快速且高效,为了提升代码质量及避免重复造轮子,有必要学习下。
无限迭代器
count(start=0, step=1)
count迭代器以start为起点(默认0),step为间隔(默认1)返回相应的值:
from itertools import count
for i in count(10,2):
if i > 20:
break
else:
print i,
输出:
10 12 14 16 18 20
除了手动添加break跳出循环外,另外一种方式,使用islice,islice实为对迭代器作分割,可以指定迭代器的起始和终止参数。
from itertools import count, islice
for i in islice(count(10,2),8): # 指定迭代到第8个
print i,
输出:
10 12 14 16 18 20 22 24
for i in islice(count(10,2),3,8): # 指定从第3个迭代到第8个
print i,
输出:
16 18 20 22 24
cycle(iterable)
cycle迭代器可以在一系列数据中无限循环
for i in islice(cycle('zxw'),8):
print i,
输出:
z x w z x w z x
for i in islice(cycle(['zxw', 'dj']),8):
print i,
输出:
zxw dj zxw dj zxw dj zxw dj
# 可以使用Python内置的next去依次遍历由itertools产生的迭代器:
rgb = ['red', 'green', 'blue']
it = cycle(rgb)
next() # 'red'
next() # 'green'
...
repeat(object[,times])
repeat会无限次地返回object,除非指定times,会在达到times次的迭代时抛出StopIteration异常。
from itertools import repeat
it = repeat('zxw', 3)
print next(it),next(it),next(it)
输出:
zxw zxw zxw
会终止的迭代器
Accumulate(iterable[,func]) (python3.2)
根据func进行累计运算,默认为加法。
>> from itertools import accumulate
>>> list(accumulate(range(10))) # 使用list返回列表,否则为迭代器
[0, 1, 3, 6, 10, 15, 21, 28, 36, 45]
chain(*iterables)
chain迭代器接收一系列可迭代对象并将其组合成一个,虽然可以用加法或extend代替,但这种方式更加优雅易懂。
from itertools import chain
a = [1,2,3,4]
b = [5,6,7,8]
c = [9,0]
print list(chain(a,b,c)) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
print list(chain.from_iterable([a,b,c])) # 与上面等效, [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
compress(data,selectors)
compress接收两个参数,使用selectors过滤data,一般selectors为bool类型列表,或者是0,1。
from itertools import compress
a = [1,2,3,4]
b = [1,0,1]
print list(compress(a,b)) # [1,3]
print list(compress(b,a)) # [1,0,1]
dropwhile(predicate,iterable),takewhile(predicate,iterable)
dropwhile使用predicate依次遍历iterable,当遇到第一个False时,返回包括该元素在内的剩下的元素列表。
from itertools import dropwhile
a = [1,2,3,4,3,2,1]
print list(dropwhile(lambda x: x < 4, a)) # [4, 3, 2, 1]
takewhile与dropwhile相反,当遇到第一个False时,返回不包括该元素的前置所有元素。
print list(takewhile(lambda x: x < 4, a)) # [1,2,3]
ifilterfalse(predicate,iterable)
filterfalse会用predicate遍历iterable中的所有元素,返回验证为False的元素列表。个人认为,对于简单的predicate,可以用列表推导代替,更加简单。
from itertools import ifilterfalse
a = [1,2,3,4,3,2,1]
print list(ifilterfalse(lambda x: x < 4, a)) # [4]
print [i for i in a if not i < 4] # [4], 列表推导方式
groupby(iterable, key=None)
groupby默认使用iterable中的当前元素作为分组的key,也可以自定义。groupby只能对序列中连续的元素进行分组。
b = [1,2,3,3,3,4,4,5,3,3]
for key, group in groupby(b):
print 'group start, key:%s' % key
for v in group:
print v
print 'group end'
输出:
group start, key:1
1 group end
group start, key:2
2 group end
group start, key:3
3 3 3 group end
group start, key:4
4 4 group end
group start, key:5
5 group end
group start, key:3
3 3 group end
a = [('a1', 'A'), ('b1', 'B'), ('c1', 'C'), ('d1', 'D'), ('a2', 'A'), ('c2', 'C')]
a.sort() # 排序,以保证能够执行分组
for key, group in groupby(a, lambda kv: kv[1]): # 使用元组内的第二个元组作为key
print 'group start, key: %s' % key
for v, k in group:
print v,
print 'group end'
输出:
group start, key: A
a1 a2 group end
group start, key: B
b1 group end
group start, key: C
c1 c2 group end
group start, key: D
d1 group end
starmap(func, iterable)
starmap与map十分类似,具体如下:
from itertools import starmap
print list(starmap(lambda x, y: x + y, [(1,2), (3,4)])) # 3,7
tee(iterable,n=2)
tee可以复制单个可迭代对象,默认生成2个迭代器
from itertools import tee
a = 'zxwdj'
it1, it2 = tee(a)
print list(it1), list(it2) # ['z', 'x', 'w', 'd', 'j'] ['z', 'x', 'w', 'd', 'j']
izip(*iterables), izip_longest(*iterables,fillvalue=None)
与zip一样,都是将序列组合成元组,zip返回的是元组列表,izip和izip_longest返回的是迭代器,所以效率更高。组合时,izip以最短序列为准,izip_longest以最长序列为准,默认补充位是None。
from itertools import izip_longest, izip
print list(izip_longest('ABCD', 'xy', fillvalue='zxw')) # [('A', 'x'), ('B', 'y'), ('C', 'zxw'), ('D', 'zxw')]
print list(izip('ABCD', 'xy', 'cde')) # [('A', 'x', 'c'), ('B', 'y', 'd')]
组合生成器
combinations(iterable,r), combinations_with_replacement(iterable,r), permutations(iterable,r)
combinations和combinations_with_replacement都是对iterable以组合长度r进行排列组合,在组合式,前者不包括自身,后者可以包括自身。permutations与combinations一样,只不过是全排列。
from itertools import combinations, combinations_with_replacement, permutations
print list(combinations('zxw',2)) # [('z', 'x'), ('z', 'w'), ('x', 'w')]
print list(combinations_with_replacement('zxw',2)) # [('z', 'z'), ('z', 'x'), ('z', 'w'), ('x', 'x'), ('x', 'w'), ('w', 'w')]
print list(permutations('zxw',2)) # [('z', 'x'), ('z', 'w'), ('x', 'z'), ('x', 'w'), ('w', 'z'), ('w', 'x')]
product(*iterables)
根据传入的序列,生成笛卡尔积。
from itertools import product
a = [1,2,3]
b = [4,5,6]
c = [(1,1), (2,2), (3,3)]
print list(product(a,b)) # [(1, 4), (1, 5), (1, 6), (2, 4), (2, 5), (2, 6), (3, 4), (3, 5), (3, 6)]
print list(product(*c)) # [(1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3), (1, 2, 3)]