文章目录
- 一、合并和分解迭代器
- 1、chain:首尾相接
- 2、zip / zip_longest:对齐取数
- 3、islice:切片
- 4、tee:分裂
- 二、转换输入
- 1、map / starmap:函数映射
- 三、生成新值
- 1、count:生成连续整数
- 2、repeat:单个值的重复
- 3、cycle:某段内容的循环重复
- 四、过滤
- 1、takewhile:获取元素直至 False
- 2、dropwhile:跳过元素直至 False
- 3、filter / filterfalse:筛选每个元素
- 4、compress:迭代器控制元素输出
- 五、数据分组
- 1、groupby:对连续相同元素分组
- 六、合并输入
- 1、accumulate:元素累加
- 2、product:笛卡尔积
- 3、permutations:元素有序排列,M个元素中选N个
- 4、combinations:元素无序组合,M个元素中选N个
- 5、combinations_with_replacement:考虑自身元素的无序组合
itertools
模块包括一组用于处理序列数据集的函数。该模块的目的是能够快速处理数据、高效使用内存,以及表述更加复杂的迭代算法。
import itertools
一、合并和分解迭代器
1、chain:首尾相接
chain
可以把多个源迭代器从头到尾连接成一个迭代器:
it = itertools.chain(iter([1, 2, 3]), ['a', 'b', 'c'])
>>> list(it): [1, 2, 3, 'a', 'b', 'c']
chain.from_iterable()
方法适用于无法提前知道源迭代器数据,或者需要采用懒方式计算的情况。注意,该方法只能传入一个参数:
def make_iterables_to_chain():yield [1, 2, 3]yield ['a', 'b', 'c']it = itertools.chain.from_iterable(make_iterables_to_chain())
>>> list(it): [1, 2, 3, 'a', 'b', 'c']
2、zip / zip_longest:对齐取数
Python 内置的zip
函数可以把多个源迭代器封装成惰性生成器(lazy generator),每次推进时会从这些源迭代器中分别获取下一个元素值,形成元组返回:
it = zip([1, 2, 3], ['a', 'b', 'c'])
>>> list(it): [(1, 'a'), (2, 'b'), (3, 'c')]
任何一个源迭代器耗尽,zip
就会停止,也就是说,zip
惰性生成器的可迭代次数,取决于最短源迭代器的可迭代次数。
itertools
模块中的zip_longest
函数会将所有的源迭代器耗尽,即使它们的可迭代次数不同。默认会把源迭代器缺少的值替换为None
,可以借助参数fillvalue
来指定缺失值的替换值:
it = itertools.zip_longest([1, 2, 3, 4], ['a', 'b', 'c'], fillvalue='missing_value')
>>> list(it): [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'missing_value')]
3、islice:切片
islice
在不拷贝数据的前提下,按照下标切割源迭代器。与列表相同,islice
同样包括开始位置start
、结束位置end
和步长step
,其中start
和step
是可选的。
# 仅配置结束位置
it = itertools.islice([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 5)
>>> list(it): [0, 1, 2, 3, 4]# 配置开始位置、结束位置和步长
it = itertools.islice(range(100), 5, 15, 2)
>>> list(it): [5, 7, 9, 11, 13]
4、tee:分裂
tee
函数可以将源迭代器分裂成多个独立的迭代器,分裂个数由第二个参数指定(默认为2)。如果分裂出的迭代器推进速度不一致,程序可能要用大量内存做缓冲,以存放进度落后的迭代器将来会用到的元素。
ori_it = [1, 2, 3, 4, 5]
it1, it2, it3 = itertools.tee(ori_it, 3)
>>> list(it1/it2/it3): [1, 2, 3, 4, 5]
即使用tee
函数创建出了新迭代器,如果源迭代器被推进,新迭代器将不会再产出被推进的值。所以创建了新迭代器后,不建议再使用源迭代器。
ori_it = iter([1, 2, 3, 4, 5])
it1, it2, it3 = itertools.tee(ori_it, 3)
next(ori_it), next(ori_it)
>>> list(it1/it2/it3): [3, 4, 5]
二、转换输入
1、map / starmap:函数映射
Python 内置的map
函数能够将源迭代器中的值作为参数,调用映射函数并返回一个迭代器。任何一个源迭代器被耗尽时,map
函数都会停止。
list1 = [1, 2, 3, 4, 5]
list2 = [0, 2, 4]result1 = map(lambda x: x**2, list1)
>>> list(result1): [1, 4, 9, 16, 25]def map_multiple(x, y):return x*y
result2 = map(map_multiple, list1, list2)
>>> list(result2): [0, 4, 12]
itertools
模块中的starmap
函数与map
函数类似,但是它是使用*
(unpacking)语法分解单个源迭代器中的元素作为映射函数的参数:
values = [(0, 5), (1, 6), (2, 7), (3, 8), (4, 9)]
it = itertools.starmap(lambda x, y: x*y, values)
>>> list(result1): [0, 6, 14, 24, 36]
可以通俗认为,传入map
函数的映射函数名为f(it1, it2)
,而传入starmap
函数的映射函数名为f(*it)
。
三、生成新值
1、count:生成连续整数
count
函数能够无限地生成连续的整数,首个生成的整数可以通过第一个参数指定(默认为0)。count
函数可以指定「开始位置」和「步长」参数,但是没有「结束位置」参数。
it = zip(itertools.count(), ['a', 'b', 'c'])
>>> list(it): [(0, 'a'), (1, 'b'), (2, 'c')]# -1 为起始整数,3 为步长
it = zip(itertools.count(-1, 3), ['a', 'b', 'c'])
>>> list(it): [(-1, 'a'), (2, 'b'), (5, 'c')]
2、repeat:单个值的重复
repeat
函数可以不停地输出某个值,允许配置第二个参数times
来限制输出次数:
it = itertools.repeat('hello', 5)
>>> list(it): ['hello', 'hello', 'hello', 'hello', 'hello']
3、cycle:某段内容的循环重复
cycle
函数可以循环地重复输出源迭代器中的各项元素。由于必须记住源迭代器的全部内容,所以如果源迭代器很长,可能会耗费大量内存。
it = zip(range(7), itertools.cycle(['a', 'b', 'c']))
>>> list(it): [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'a'), (4, 'b'), (5, 'c'), (6, 'a')]
四、过滤
1、takewhile:获取元素直至 False
takewhile
函数会一直从源迭代器中获取元素,直至判断函数返回False
,停止输出该元素,也不会再判断后续元素:
it = itertools.takewhile(lambda x: x < 2, [-1, 0, 1, 2, -2])
>>> list(it): [-1, 0, 1]
2、dropwhile:跳过元素直至 False
与takewhile
函数相反,dropwhile
函数会一直跳过源迭代器中的元素,直至判断函数返回False
,开始输出该元素及后续元素(后续不再判断):
it = itertools.dropwhile(lambda x: x < 2, [-1, 0, 1, 2, -2])
>>> list(it): [2, -2]
3、filter / filterfalse:筛选每个元素
Python 内置的filter
函数能够从源迭代器中筛选出判断函数返回True
的元素,并返回一个迭代器。filter
函数会测试每一个元素。
it = filter(lambda x: x%2 == 0, [1, 2, 3, 4, 5])
>>> list(it): [2, 4]
itertools
模块中的filterfalse
函数恰好与filter
函数相反,从源迭代器中筛选出判断函数返回False
的元素。同样,filterfalse
函数会测试每一个元素。
it = itertools.filterfalse(lambda x: x%2 == 0, [1, 2, 3, 4, 5])
>>> list(it): [1, 3, 5]
4、compress:迭代器控制元素输出
compress
函数使用第二个源迭代器的布尔元素来判断,对第一个源迭代器的元素是输出还是跳过。两个迭代器中的任何一个被耗尽,都会停止输出。
it = itertools.compress(range(1, 10), [True, False, False, True, False])
>>> list(it): [1, 4]
五、数据分组
1、groupby:对连续相同元素分组
groupby
函数用于对源迭代器中连续相同的元素进行分组,生成的迭代器每次生成一个(key, group)
对,key
是分组的键值,group
是一个子迭代器,包含当前组的所有元素。
for key, group in itertools.groupby('AAAABBBCCD'):print(key, list(group))
>>> 输出结果:A ['A', 'A', 'A', 'A']B ['B', 'B', 'B']C ['C', 'C']D ['D']for key, group in itertools.groupby([('a', 1), ('a', 2), ('b', 3), ('b', 4), ('c', 5)], lambda x: x[0]):print(key, list(group))
>>> 输出结果:a [('a', 1), ('a', 2)]b [('b', 3), ('b', 4)]c [('c', 5)]
请注意,如果相同的元素不连续,会被分到不同的组。因此,如果要将所有相同的元素分组而不管是否连续,通常需要先对数据进行排序。
for key, group in itertools.groupby([1, 2, 2, 3, 4, 4, 4, 1, 1, 3]):print(key, list(group))
>>> 输出结果:1 [1]2 [2, 2]3 [3]4 [4, 4, 4]1 [1, 1]3 [3]
六、合并输入
1、accumulate:元素累加
accumulate
函数会对源迭代器中的元素进行累加,每次累加都会生成一个元素。可以指定表示累加逻辑的函数,该函数可以是任何的双参数函数,默认逻辑是两值相加。
it1 = itertools.accumulate(range(5))
>>> list(it1): [0, 1, 3, 6, 10]it2 = itertools.accumulate('abcde')
>>> list(it2): ['a', 'ab', 'abc', 'abcd', 'abcde']it = itertools.accumulate('abcde', lambda x, y: y + x + y)
>>> list(it): ['a', 'bab', 'cbabc', 'dcbabcd', 'edcbabcde']
accumulate
函数和functools
模块里的reduce
函数类似,但是后者只会给出最终的累计值:
import functools
# result 等于 45
result = functools.reduce(lambda x, y: x + y, range(10))
2、product:笛卡尔积
product
函数从一个或者多个源迭代器中获取元素,并计算笛卡尔积。它可以取代多层嵌套的for
循环。要计算源迭代器与自身的积,可以使用参数repeat
指定输入重复多少次。
single = itertools.product([1, 2], repeat=2)
>>> list(single): [(1, 1), (1, 2), (2, 1), (2, 2)]multiple = itertools.product([1, 2], ['a', 'c'])
>>> list(multiple): [(1, 'a'), (1, 'c'), (2, 'a'), (2, 'c')]
3、permutations:元素有序排列,M个元素中选N个
permutations
函数将源迭代器中的元素以指定长度进行有序排列,默认(不指定长度)会生成所有排列的全集(长度为源迭代器中元素个数)。使用r
参数指定所返回排列的长度。
it1 = itertools.permutations('abc')
>>> list(it1): [('a', 'b', 'c'), ('a', 'c', 'b'), ('b', 'a', 'c'), ('b', 'c', 'a'), ('c', 'a', 'b'), ('c', 'b', 'a')]it2 = itertools.permutations('abc', r=2)
>>> list(it2): [('a', 'b'), ('a', 'c'), ('b', 'a'), ('b', 'c'), ('c', 'a'), ('c', 'b')]
4、combinations:元素无序组合,M个元素中选N个
combinations
函数将源迭代器中的元素以指定长度进行无序组合。与permutations
函数不同的是,该函数的 r 参数是必要参数。只要源迭代器的元素取值是唯一的,输出就不会包含任何重复的值。
it = itertools.combinations('abca', r=2)
>>> list(it): [('a', 'b'), ('a', 'c'), ('a', 'a'), ('b', 'c'), ('b', 'a'), ('c', 'a')]
5、combinations_with_replacement:考虑自身元素的无序组合
与combinations
函数不同的是,combinations_with_replacement
函数会将当前元素与「当前元素、所有的其他元素」均进行配对:
it = itertools.combinations_with_replacement('abcd', r=2)
>>> list(it): [('a', 'a'), ('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'b'), ('b', 'c'), ('b', 'd'), ('c', 'c'), ('c', 'd'), ('d', 'd')]