高效的 itertools 模块
我们知道,迭代器的特点是:惰性求值(Lazy evaluation),即只有当迭代至某个值时,它才会被计算,这个特点使得迭代器特别适合于遍历大文件或无限集合等,因为我们不用一次性将它们存储在内存中。
Python 内置的 itertools 模块包含了一系列用来产生不同类型迭代器的函数或类,这些函数的返回都是一个迭代器,我们可以通过 for 循环来遍历取值,也可以使用 next()
itertools 模块提供的迭代器函数有以下几种类型:
- 无限迭代器:生成一个无限序列,比如自然数序列
1, 2, 3, 4, ...
- ;
- 有限迭代器:接收一个或多个序列(sequence)作为参数,进行组合、分组和过滤等;
- 组合生成器:序列的排列、组合,求序列的笛卡儿积等;
无限迭代器
itertools 模块提供了三个函数(事实上,它们是类)用于生成一个无限序列迭代器:
- count(firstval=0, step=1)
创建一个从 firstval (默认值为 0) 开始,以 step (默认值为 1) 为步长的的无限整数迭代器 - cycle(iterable)
对 iterable 中的元素反复执行循环,返回迭代器 - repeat(object [,times]
反复生成 object,如果给定 times,则重复次数为 times,否则为无限
下面,让我们看看一些例子。
count
count()
>>> import >>> >>> nums = itertools.count() >>> for i in ... if i > 6: ... break ... 0 1 2 3 4 5 6 >>> nums = itertools.count( 10, 2) # 指定开始值和步长 >>> for i in ... if i > 20: ... break ... 10 12 14 16 18 20 |
cycle
cycle()
>>> import >>> >>> cycle_strings = itertools.cycle( 'ABC') >>> i = 1 >>> for string in ... if i == 10: ... break ... i += 1 ... 1 2 3 4 5 6 7 8 9 |
repeat
repeat()
>>> import >>> >>> for item in itertools.repeat( 'hello world', 3): ... hello world hello world hello world >>> >>> for item in itertools.repeat([ 1, 2, 3, 4], 3): ... 1, 2, 3, 4] 1, 2, 3, 4] 1, 2, 3, 4] |
有限迭代器
itertools 模块提供了多个函数(类),接收一个或多个迭代对象作为参数,对它们进行组合、分组和过滤等:
- chain()
- compress()
- dropwhile()
- groupby()
- ifilter()
- ifilterfalse()
- islice()
- imap()
- starmap()
- tee()
- takewhile()
- izip()
- izip_longest()
chain
chain
chain(iterable1, iterable2, iterable3, ...) |
chain
>>> from itertools import >>> >>> for item in chain([ 1, 2, 3], [ 'a', 'b', 'c']): ... 1 2 3 a b c |
chain
chain.from_iterable(iterable) |
接收一个可迭代对象作为参数,返回一个迭代器:
>>> from itertools import >>> >>> string = chain.from_iterable( 'ABCD') >>> string.next() 'A' |
compress
compress
compress(data, selectors) |
compress
>>> from itertools import >>> >>> list(compress( 'ABCDEF', [ 1, 1, 0, 1, 0, 1])) 'A', 'B', 'D', 'F'] >>> list(compress( 'ABCDEF', [ 1, 1, 0, 1])) 'A', 'B', 'D'] >>> list(compress( 'ABCDEF', [ True, False, True])) 'A', 'C'] |
dropwhile
dropwhile
dropwhile(predicate, iterable) |
其中,predicate 是函数,iterable 是可迭代对象。对于 iterable 中的元素,如果 predicate(item) 为 true,则丢弃该元素,否则返回该项及所有后续项。
>>> from itertools import >>> >>> list(dropwhile( lambda x: x < 5, [ 1, 3, 6, 2, 1])) 6, 2, 1] >>> >>> list(dropwhile( lambda x: x > 3, [ 2, 1, 6, 5, 4])) 2, 1, 6, 5, 4] |
groupby
groupby
groupby(iterable[, keyfunc]) |
其中,iterable 是一个可迭代对象,keyfunc 是分组函数,用于对 iterable 的连续项进行分组,如果不指定,则默认对 iterable 中的连续相同项进行分组,返回一个 (key, sub-iterator)
>>> from itertools import >>> >>> for key, value_iter in groupby( 'aaabbbaaccd'): ... print key, ':', list(value_iter) ... 'a', 'a', 'a'] 'b', 'b', 'b'] 'a', 'a'] 'c', 'c'] 'd'] >>> >>> data = [ 'a', 'bb', 'ccc', 'dd', 'eee', 'f'] >>> for key, value_iter in groupby(data, len): # 使用 len 函数作为分组函数 ... print key, ':', list(value_iter) ... 1 : [ 'a'] 2 : [ 'bb'] 3 : [ 'ccc'] 2 : [ 'dd'] 3 : [ 'eee'] 1 : [ 'f'] >>> >>> data = [ 'a', 'bb', 'cc', 'ddd', 'eee', 'f'] >>> for key, value_iter in ... print key, ':', list(value_iter) ... 1 : [ 'a'] 2 : [ 'bb', 'cc'] 3 : [ 'ddd', 'eee'] 1 : [ 'f'] |
ifilter
ifilter
ifilter(function or None, sequence) |
将 iterable 中 function(item) 为 True 的元素组成一个迭代器返回,如果 function 是 None,则返回 iterable 中所有计算为 True 的项。
>>> from itertools import >>> >>> list(ifilter( lambda x: x < 6, range( 10))) 0, 1, 2, 3, 4, 5] >>> >>> list(ifilter( None, [ 0, 1, 2, 0, 3, 4])) 1, 2, 3, 4] |
ifilterfalse
的使用形式和 ifilter
>>> from itertools import >>> >>> list(ifilterfalse( lambda x: x < 6, range( 10))) 6, 7, 8, 9] >>> >>> list(ifilter( None, [ 0, 1, 2, 0, 3, 4])) 0, 0] |
islice
islice
islice(iterable, [start,] stop [, step]) |
其中,iterable 是可迭代对象,start 是开始索引,stop 是结束索引,step 是步长,start 和 step 可选。
>>> from itertools import >>> >>> list(islice([ 10, 6, 2, 8, 1, 3, 9], 5)) 10, 6, 2, 8, 1] >>> >>> list(islice(count(), 6)) 0, 1, 2, 3, 4, 5] >>> >>> list(islice(count(), 3, 10)) 3, 4, 5, 6, 7, 8, 9] >>> list(islice(count(), 3, 10 , 2)) 3, 5, 7, 9] |
imap
imap
类似 map
imap(func, iter1, iter2, iter3, ...) |
imap
返回一个迭代器,元素为 func(i1, i2, i3, ...)
,i1
,i2
等分别来源于 iter
, iter2
。
>>> from itertools import >>> >>> imap(str, [ 1, 2, 3, 4]) 0x10556d050> >>> >>> list(imap(str, [ 1, 2, 3, 4])) '1', '2', '3', '4'] >>> >>> list(imap(pow, [ 2, 3, 10], [ 4, 2, 3])) 16, 9, 1000] |
tee
tee
tee(iterable [,n]) |
tee
>>> from itertools import >>> >>> tee( 'abcd') # n 默认为 2,创建两个独立的迭代器 0x1049957e8>, <itertools.tee object at 0x104995878>) >>> >>> iter1, iter2 = tee( 'abcde') >>> list(iter1) 'a', 'b', 'c', 'd', 'e'] >>> list(iter2) 'a', 'b', 'c', 'd', 'e'] >>> >>> tee( 'abc', 3) # 创建三个独立的迭代器 0x104995998>, <itertools.tee object at 0x1049959e0>, <itertools.tee object at 0x104995a28>) |
takewhile
takewhile
takewhile(predicate, iterable) |
其中,predicate 是函数,iterable 是可迭代对象。对于 iterable 中的元素,如果 predicate(item) 为 true,则保留该元素,只要 predicate(item) 为 false,则立即停止迭代。
>>> from itertools import >>> >>> list(takewhile( lambda x: x < 5, [ 1, 3, 6, 2, 1])) 1, 3] >>> list(takewhile( lambda x: x > 3, [ 2, 1, 6, 5, 4])) [] |
izip
izip
用于将多个可迭代对象对应位置的元素作为一个元组,将所有元组『组成』一个迭代器,并返回。它的使用形式如下:
izip(iter1, iter2, ..., iterN) |
如果某个可迭代对象不再生成值,则迭代停止。
>>> from itertools import >>> >>> for item in izip( 'ABCD', 'xy'): ... 'A', 'x') 'B', 'y') >>> for item in izip([ 1, 2, 3], [ 'a', 'b', 'c', 'd', 'e']): ... 1, 'a') 2, 'b') 3, 'c') |
izip_longest
跟 izip
izip_longest(iter1, iter2, ..., iterN, [fillvalue=None]) |
如果有指定 fillvalue,则会用其填充缺失的值,否则为 None。
>>> from itertools import >>> >>> for item in izip_longest( 'ABCD', 'xy'): ... 'A', 'x') 'B', 'y') 'C', None) 'D', None) >>> >>> for item in izip_longest( 'ABCD', 'xy', fillvalue= '-'): ... 'A', 'x') 'B', 'y') 'C', '-') 'D', '-') |
组合生成器
itertools 模块还提供了多个组合生成器函数,用于求序列的排列、组合等:
- product
- permutations
- combinations
- combinations_with_replacement
product
product
product(iter1, iter2, ... iterN, [repeat=1]) |
其中,repeat 是一个关键字参数,用于指定重复生成序列的次数,
>>> from itertools import >>> >>> for item in product( 'ABCD', 'xy'): ... 'A', 'x') 'A', 'y') 'B', 'x') 'B', 'y') 'C', 'x') 'C', 'y') 'D', 'x') 'D', 'y') >>> >>> list(product( 'ab', range( 3))) 'a', 0), ( 'a', 1), ( 'a', 2), ( 'b', 0), ( 'b', 1), ( 'b', 2)] >>> >>> list(product(( 0, 1), ( 0, 1), ( 0, 1))) 0, 0, 0), ( 0, 0, 1), ( 0, 1, 0), ( 0, 1, 1), ( 1, 0, 0), ( 1, 0, 1), ( 1, 1, 0), ( 1, 1, 1)] >>> >>> list(product( 'ABC', repeat= 2)) 'A', 'A'), ( 'A', 'B'), ( 'A', 'C'), ( 'B', 'A'), ( 'B', 'B'), ( 'B', 'C'), ( 'C', 'A'), ( 'C', 'B'), ( 'C', 'C')] >>> |
permutations
permutations
permutations(iterable[, r]) |
其中,r 指定生成排列的元素的长度,如果不指定,则默认为可迭代对象的元素长度。
>>> from itertools import >>> >>> permutations( 'ABC', 2) 0x1074d9c50> >>> >>> list(permutations( 'ABC', 2)) 'A', 'B'), ( 'A', 'C'), ( 'B', 'A'), ( 'B', 'C'), ( 'C', 'A'), ( 'C', 'B')] >>> >>> list(permutations( 'ABC')) 'A', 'B', 'C'), ( 'A', 'C', 'B'), ( 'B', 'A', 'C'), ( 'B', 'C', 'A'), ( 'C', 'A', 'B'), ( 'C', 'B', 'A')] >>> |
combinations
combinations
combinations(iterable, r) |
其中,r 指定生成组合的元素的长度。
>>> from itertools import >>> >>> list(combinations( 'ABC', 2)) 'A', 'B'), ( 'A', 'C'), ( 'B', 'C')] |
combinations_with_replacement
和 combinations
>>> from itertools import >>> >>> list(combinations_with_replacement( 'ABC', 2)) 'A', 'A'), ( 'A', 'B'), ( 'A', 'C'), ( 'B', 'B'), ( 'B', 'C'), ( 'C', 'C')] |
小结
- itertools 模块提供了很多用于产生多种类型迭代器的函数,它们的返回值不是 list,而是迭代器。