itertools 是实现各种迭代生成的工具, 尤其重要的是可以实现排列和组合的问题. 返回的一般都是迭代器.
合并之前三篇相关的内容
一. 组合式迭代器
1. product
能够从多个迭代器中各自取值组成组合,生成的元组数量为N*M*O...
. 实际上可以用多个for-loop来实现. 但如果输入数量不确认时, 用for循环就不太好写了. 因此更建议用prodcut实现.
格式是: product(*iterables, repeat=1)
, 相当于多层次的for循环嵌套, 第一层是第一个迭代器, 以此类推. 当使用repeat=N
时, 就是迭代N次前面的迭代器. 适合重复迭代某一个迭代器.
product('ab', range(3))
#--> ('a',0) ('a',1) ('a',2) ('b',0) ('b',1) ('b',2)
product((0,1), (0,1), (0,1))
#--> (0,0,0) (0,0,1) (0,1,0) (0,1,1) (1,0,0)
product('ab', repeat=2)
#--> ('a', 'a'), ('a', 'b'), ('b', 'a'), ('b', 'b')
a = [range(2), range(3)]
product(*a)
#--> (0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)
2. combinations
组合问题的解法, 返回的是N个元素选取r个的组合, 而且是有序的 (从小到大).
格式是: combinations(iterable, r)
, 返回生成 r 元元组的迭代器. 元组数量是r(上标)N(下标)C
的数量. 返回的元组内的元素顺序依从原迭代器器内的元素的顺序. 当输入迭代器是有序且无重复时, 返回的是无重复的有序的元组的迭代器.
由于是一个组合问题, 所以当输入的列表含有相同元素时, 也会生成含有重复数值的元组. 但这个只是数值重复, 来源是来于不同位置.
from itertools import combinations
combinations(range(4), 3)
#--> (0,1,2), (0,1,3), (0,2,3), (1,2,3)
combinations([1,1,2], 2)
#--> (1, 1), (1, 2), (1, 2)
3. permutations
排列问题的解法, 返回的是N个元素选取r个的组合, 无序组合, 因此实际是排列问题.
格式是: permutations(iterable[, r])
, 返回生成 r 元元组的迭代器(不指名r时, r为迭代器的长度). 元组数量是r(上标)N(下标)A
的数量.
实际上是取不同元素进行排列, 因此如果输入的迭代器含有相同值得元素时, 输出的元组也可能出现重复值, 但实际来源于不同元素.
from itertools import permutations
permutations(range(3), 2)
#--> (0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)
permutations([1,1,2], 2)
#--> (2, 1), (2, 2), (1, 2), (1, 2), (2, 2), (2, 1)
4. combinations_with_replacement
放回式组合问题. 在普通组合中, 一个元素只能用一次. 该方法运行多次.
格式是: combinations_with_replacement(iterable, r)
, 和combinations一样. 和排列不一样的是, 元素的排列始终是有序的, 例如'ABCD'
, combinations_with_replacement会出现AA,AB, 不会出现BA. 差别可参考下列三个循环:
- combinations:
for i in range(4) for j in range(j+1, 4) ...
- combinations_with_replacement:
for i in range(4) for j in range(j,4)...
- permutations:
for i in range(4) for j in range(4) ...
combinations_with_replacement('ABCD', 2)
#--> AA AB AC AD BB BC BD CC CD DD
求排列组合和阶乘:
from scipy import special
special.perm(5,2)
-> 排列A5,2的值. 20special.com(5.2)
-> 组合C5,2的值, 10.special.factorial(5)
-> 阶乘5, 120.
itertools还有两类迭代器, 一种是无穷迭代处理, 一种是对有限输入进行迭代处理. 官方叫: Infinite iterators
和Iterators terminating on the shortest input sequence
.
二. 无穷迭代器
实现无穷迭代, 一般配合for和判断条件来打断.
1. count
不断递增数值, 格式count(start=0 [,step=1])
, 支持参数是递增值. 例如: count(10) --> 10 11 12 13 14 ...
2. cycle
对指定迭代对象不断迭代. 格式: cycle(iterable)
, 例如: cycle('ABCD') --> A B C D A B C D ...
3. repeat
重复某个值无穷次或指定次数, 格式是repeat(object [,times])
, times是重复次数, 默认是无穷循环. 例如repeat(10,3) --> 10 10 10
.
三. 有限处理迭代器
accumulate 累加
accumulate(p [, function])
: 对之前的结果进行累加, 也可以自定义处理函数. 实际是result=a0, result+=a1, result+=a2, result+=a3....
例如: accumulate([1,2,3,4,5]) --> 1 3 6 10 15
chain 迭代器整合
将多个迭代器组合一起进行叠加, 例如chain(iter1, iter2, iter3)
, 迭代完第一个迭代器后接着迭代第二个. 其实就是把多个迭代器组合一起形成一个新迭代器. 挺重要的.
如果输入是迭代器包含迭代器, 例如iterlist=['ABC', 'DEF']
, 可以使用chain(*iterlist)
, 也可以使用chain.from_iterable(iterlist)
.
takewhile dropwhile 按条件取舍迭代器.
这两个方法类似, takewhile是条件满足时留下, dropwhile是条件满足时抛弃.
- 对于takewhile, 会循环迭代器, 并交给pred预测, 如果是True, 则返回值并继续迭代, 如果是False, 不返回值, 并断开迭代.
- 对于dropwhile, 也是循环交给pred, 如果是True, 则抛弃继续迭代, 如果是False, 则终止判断, 将后面的元素迭代返回.
- takewhile和dropwhile组合起来, 就是原始迭代器的内容.
格式: dropwhile(predicate, iterable)
, pred是一个 pred(item)
函数对象, 返回True/False. 最简单的是采用lambda
来组合完成.
takewhile(lambda x: x<5, [1,4,6,4,1])
#--> 1 4
dropwhile(lambda x: x<5, [1,4,6,4,1])
#--> 6 4 1
filterfalse 提取假的结果
格式是filterfalse(function or None, sequence)
, 如不指明判断的函数, 则会使用bool
来判断. 返回的是迭代器元素进行 function(item)
后返回假的元素.
filterfalse(lambda x: x%2, range(10))
#--> 0 2 4 6 8
startmap 接受一个参数迭代器的map
startmap和map
类似, 但接受的可以是函数参数已放好在迭代器中的迭代器. 例如pow
函数接受两个参数, 使用map
需要两个迭代器分别传递参数, 而startmap
则可以采用一个迭代器, 迭代器产生的是所需参数的元组.
格式: starmap(function, sequence)
. map和startmap参数之间的转化也可以用zip
来进行.
map(pow, range(10), repeat(2))
#-> 0, 1, 4, 9, 16, 25 .... 81
map(pow, [2,3,10], [5,2,3])
# --> 32 9 1000
starmap(pow, [(2,5), (3,2), (10,3)])
# --> 32 9 1000
para = zip( [(2,5), (3,2), (10,3)] )
# [(2,3,10), (5,2,3)]
map(*para)
# --> 32 9 1000
tee 迭代器复制
从一个原始迭代器返回n个独立不受干扰的迭代器. 实际测试中, 生成的n个迭代器中, 第一个和原始迭代器是同步的, 而后面的是完全独立, 和原始迭代器无关的. 生成的迭代器的状态和tee时的状态是一致的.
格式: tee(iterable, n=2)
注意不能明参n=3
, 只能tee(iterable, 3)
. 返回有n个迭代器的元组.
a = itertools.chain(range(3),range(3,10))
a.__next__(); a.__next__()
# -> 1 # 下一个生成数是2
# b = itertools.tee(a,3) will get error
b = itertools.tee(a,3)
b[0].__next__() #-> 2
a.__next__() #-> 3
b[1].__next__() #-> 2
b[0].__next__() #-> 4
b[2].__next__() #-> 2
islice 分片器(元素选择器)
能够实现类似分片的效果, 从迭代器中取出指定范围的元素. 如果stop是None
, 相当于[start:]
效果, 迭代到底.
格式是: itertools.islice(iterable, stop)
或itertools.islice(iterable, start, stop[, step])
.
islice('ABCDEFG', 2) --> A B == [:2]
islice('ABCDEFG', 2, 4) --> C D == [2:4]
islice('ABCDEFG', 2, None) --> C D E F G == [2:]
islice('ABCDEFG', 0, None, 2) --> A C E G == [0::2], [::2]
compress 根据选择器选取结果
格式是compress(data, selectors)
, 其中data和selectors都是迭代器, 如果selectors出来的值是True或等价的值, 则返回相应data的元素的值. 如果两个迭代器长度不等, 根据短的进行处理(长的多出来的部分忽略, 不会报错).
compress('ABCDEF', [1,0,1,0,1,1])
# --> A C E F
groupby 连续重复的归为一组
格式: groupby(iterable, key=None)
对迭代器进行迭代, 根据key函数处理的值(如无, 则按元素的值进行判断)来判断元素是否和上一个元素相对, 是的话归为一组, 不是的话则创建一个新组, 新组的组名(组值)就是该元素. 类似unix命令的uniq
.
# 根据字符串重复值分组, 查看相应组key和值
[k for k, g in groupby('AAAABBBCCDAABBB')]
# --> A B C D A B
[list(g) for k, g in groupby('AAAABBBCCD')]
# --> AAAA BBB CC D
# 假设有一个数据集, 想根据keyfunc来对内容进行排序并分组. 可以:
groups = []
uniquekeys = []
data = sorted(data, key=keyfunc)
for k, g in groupby(data, keyfunc):
groups.append(list(g)) # Store group iterator as a list
uniquekeys.append(k)
zip_longest
和zip类似, 将两个迭代器的值放在一起返回二元元组. 但是zip长度不等会报错, 而zip_longest则支持长度不等. 当长度不等时, 短的迭代器部分使用None
或者指定的内容
格式: zip_longest(*iterables, fillvalue=None)
, 返回 [(A,a), (B,b)....(F, None)]
zip_longest('ABCD', 'xy', fillvalue='-')
# --> (A,x) (B,y) (C,-) (D,-)
zip_longest('ABCD', 'abc')
#--> (A, a), (B,b), (C,c)
网友评论