python itertools 使用详解

文章目录

  • (一)itertools 的所有函数说明
    • 无穷迭代器包含的 函数列表
    • 1、count( start [,step])
    • 2、cycle( iterable )
    • 3、repeat( elem [,n] )
    • 4 、accumulate( p [,func] )
    • 5、chain( p, q, … )
    • 6. chain.from_iterable(iterable)
    • 7、compress(data, selectors)
    • 8、dropwhile(func, iterable)
    • 9、filterfalse(func, iterable)
    • 10、groupby(iterable, key=None)
    • 11、islice(iterable, start, stop[, step ])
    • 12、starmap(function, iterable)
    • 13、takewhile(predicate, iterable)
    • 14、tee(iterable, n=2)
    • 15、zip_longest(*iterables, fillvalue=None)
  • 排列组合迭代器:
    • 1、product(*iterables, repeat=1)
    • 2、permutations(iterable, r=None)
    • 3、combinations(iterable, r)
    • 4、combinations_with_replacement(iterable, r)

(一)itertools 的所有函数说明

无穷迭代器包含的 函数列表

迭 代 器 说明
count( start [,step]) 创建一个从 start 开始,步长为 step 的迭代器,默认为1。
cycle( iterable ) 创建一个从 iterable 中 循环 取出元素的迭代器。
repeat( elem [,n] ) 重复 elem元素 n次。 n为空时,重复无穷次。
accumulate( p [,func] ) 创建一个迭代器,返回累加和或其他二元函数的累加结果。
chain( p, q, … ) 把可迭代对象p, q 中的元素连接起来。
chain.from_iterable( iterable ) 要求iterable对象中的元素也是可迭代的,然后把元素中元素创建一个迭代器
compress(data, selectors) 创建一个迭代器,它返回data 中经selectors 真值测试为True 的元素。
dropwhile(predicate, iterable) 创建一个迭代器,如果predicate 为true,迭代器丢弃这些元素,然后返回其他元素。
filterfalse(predicate, iterable) 创建一个迭代器,只返回iterable 中predicate 为False 的元素。
groupby(iterable, key=None) 创建一个迭代器,对里面的元素 按 key 进行分组。
islice(iterable, start, stop[, step ]) 创建一个迭代器,返回从iterable 里选中的元素。如果start 不是0,跳过iterable 中的元素,直到到达start 这个位置。之后迭代器连续返回元素,除非step 设置的值很高导致被跳过。
starmap(function, iterable) 类似 map(),function函数历遍 iterable中的元素。
takewhile(predicate, iterable) 创建一个迭代器,只要predicate 为真就从可迭代对象中返回元素。
tee(iterable, n=2) 从一个可迭代对象中返回n 个独立的迭代器。
zip_longest(*iterables, fillvalue=None) 创建一个迭代器,从每个可迭代对象中收集元素。如果可迭代对象的长度未对齐,将根据fillvalue 填充缺失值。

1、count( start [,step])

创建一个从 start 开始,步长为 step 的迭代器,默认为1。

import itertools

"""生成一个 从 10 开始,步长为 2 的无穷迭代器。不知道如果超过了sys.maxsize,会怎样,没尝试过"""
for i in itertools.count(10,2): 
    print(i)
    if i >= 30:
        break

运行结果:

10
12
14
16
18
20
22
24
26
28
30

2、cycle( iterable )

创建一个迭代器,内容是不断循环的从 迭代对象 iterable 中取出的元素。

import itertools

for i in itertools.cycle('abc'):
    print(i)

运行结果:

a
b
c
a
b
c
……  # 不断循环下去

3、repeat( elem [,n] )

创建一个迭代器, 内容是重复 n 次 elem 元素。如果没有 n 参数,则无限重复。

import itertools

for i in itertools.repeat('abc', 3):
    print(i)

运行结果:

abc
abc
abc    # 重复 3 次。

Process finished with exit code 0

4 、accumulate( p [,func] )

说明:参数 p 是一个迭代器,设里面的元素为 p0, p1, p2,p3 ……
func 默认是 求和
返回一个迭代器 t,内容是 :
python itertools 使用详解_第1张图片

import itertools

list_num = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

it = itertools.accumulate(list_num)

print(list(it))

运行结果为:

[1, 3, 6, 10, 15, 21, 28, 36, 45, 55]

Process finished with exit code 0

5、chain( p, q, … )

创建一个迭代器,它首先返回第一个可迭代对象中所有元素,接着返回下一个可迭代对象中所有元素,直到耗尽所有可迭代对象中的元素。可将多个序列处理为单个序列。

import itertools

list_num = [1, 2, 3, 4, 5,]
list_cha = ['a', 'b', 'c', 'd']

it = itertools.chain(list_num,list_cha)

print(list(it))

运行结果:

[1, 2, 3, 4, 5, 'a', 'b', 'c', 'd']

Process finished with exit code 0

6. chain.from_iterable(iterable)

创建一个迭代器,要求参数 iterable 中的每个元素还是可迭代的,它会把每个元素再迭代一次。
其实可以这样理解:这里的参数 iterable,就是上面 5 、chain( p, q, … ) 中 参数的“集合”, iterable = ( p, q, … )

import itertools

list_cha = ['aaa', 'bbb', 'ccc', [1,2,3]]

""" 会把 list_cha 中每个元素取出来,再对每个元素进行一次迭代。 """
it = itertools.chain.from_iterable(list_cha)

print(list(it))

运行结果:

['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 1, 2, 3]

Process finished with exit code 0

7、compress(data, selectors)

创建一个迭代器,根据selectors 序列的值对data 序列的元素进行过滤。如果selector[0]为真,则保留data[0] ,如果selector[1]为真,则保留data[1] … 依此类推。迭代器在两者较短的长度处停止。

import itertools

list_num = [  1,     0,    True,   0,    1,]
list_cha = ['aaa', 'bbb', 'ccc', 'ddd']

""" 根据 list_num 对 list_cha 进行筛选 """
it = itertools.compress(list_cha, list_num)     

print(list(it))

运行结果:

['aaa', 'ccc']

Process finished with exit code 0

8、dropwhile(func, iterable)

创建一个迭代器,如果 func 为 True,迭代器丢弃这些元素,直到 func 为 False,迭代过程立刻停止,返回从 False 处到结尾的所有元素。注意,迭代器在 func 首次为false 之前不会产生任何输出,所以可能需要一定长度的启动时间。

注解: 8 和 9 的函数主要是为了剔除元素,所有 把需要剔除的元素 传入判断函数,然后返回 真值 即可。

import itertools

list_num = [1, 2, 3, 4, 5, 6, 7, 8, 1, 2]

def func(x):
    if x > 5:
        return False
    else:
        return True
        
""" 调用 func 函数对 list_num 中的元素进行判断,判断结果为真时,就丢弃这个元素。
    当遇到 False 时,则停止判断,把后续的所有内容添加到生成的迭代器中。"""
it = itertools.dropwhile(func, list_num)
print(list(it))

运行结果:

[6, 7, 8, 1, 2]

9、filterfalse(func, iterable)

8、dropwhile(func, iterable) 类似,不过这个它会判断 iterable 中所有的元素。
创建一个迭代器,对 iterable 中每个元素进行判断,如果 func 为true,迭代器丢弃这些元素,然后返回其他元素。
如果 func 是None,则直接对元素进行 bool 值判读,删除 bool == True 的元素,保留 bool == False 的元素。

注解:8 和 9 的函数主要是为了剔除元素,所有 把需要剔除的元素 传入判断函数,然后返回 真值 即可。

import itertools

list_num = [1, 2, 3, 4, 5, 6, 7, 8, 0, 2]

def func(x):
    if x > 5:
        return False
    else:
        return True
        
""" 调用 func 函数对 list_num 中的每个元素进行判断,判断结果为真时,就丢弃这个元素。
    保留 func 为 False 的元素。"""
it = itertools.filterfalse(func,list_num)
print(list(it))

运行结果为:

[6, 7, 8]

另外 当 func = None 是,filterfalse 会直接判断里面的元素的bool值,然后删除 bool == True 的值。如下:

import itertools

list_num = [1, 2, 3, False, 5, 6, 7, 8, 0, 2]

it = itertools.filterfalse(None,list_num)

print(list(it))

运行结果为:

[False, 0]

10、groupby(iterable, key=None)

创建一个 迭代器,里面的元素 是 按照 Key 进行分组的。
迭代器中的元素格式类似:{ key1: [a0,a1,…], key2: [b0,b1,…], key3: [c0,c1,…]}
key 对应的分组内容 也是一个 迭代器

所以参数 key 得是一个函数,它能对 iterable 中的元素进行分类,return返回的就是key的名称。
注:使用 groupby() 函数之前,需对里面的元素按 key 进行排序。因为它分组是根据临近的元素,如果它们key一样就分到一组。

如下例子1:
情况1:里面的元素 已经 按 key 进行排序了。运行后得出的结果是正确分组的。

from itertools import groupby

# 字典中的元素,已经按 班级 排序好了。
dic = [{'class': '1 班', 'name':'小红'},
       {'class': '1 班', 'name':'小明'},
       {'class': '2 班', 'name':'李雷'},
       {'class': '2 班', 'name':'韩梅梅'},
       {'class': '3 班', 'name':'熊二'},
       {'class': '3 班', 'name':'熊大'},
       ]

def func(i):    # 定义一个 供 key 调用的函数,按return返回的值 进行分组。
    return i['class']

ite = groupby(dic, key=func)

for k, item in ite:
	# 因为 item 也是一个 迭代器,所以可以用 list 把它的元素显示出来。
    print(f'key 为:{k};  对应分组的内容为:{list(item)}')

运行结果为:

key 为:1 班;  对应分组的内容为:[{'class': '1 班', 'name': '小红'}, {'class': '1 班', 'name': '小明'}]
key 为:2 班;  对应分组的内容为:[{'class': '2 班', 'name': '李雷'}, {'class': '2 班', 'name': '韩梅梅'}]
key 为:3 班;  对应分组的内容为:[{'class': '3 班', 'name': '熊二'}, {'class': '3 班', 'name': '熊大'}]

Process finished with exit code 0

情况2:里面的元素 按 key 进行排序。运行后得出的结果是没有正确分组

from itertools import groupby

dic = [{'class': '1 班', 'name':'小红'},
       {'class': '3 班', 'name':'熊二'},      # 把 班级 3 放在班级 1中间。
       {'class': '1 班', 'name':'小明'},
       {'class': '2 班', 'name':'李雷'},
       {'class': '2 班', 'name':'韩梅梅'},
       {'class': '3 班', 'name':'熊大'},
       ]

def func(i):
    return i['class']

ite = groupby(dic, key=func)

for k, item in ite:
    print(f'key 为:{k};  对应分组的内容为:{list(item)}')

运行结果为(不是我们想要的,1班 和 3班 没有各自分组到一起):

key 为:1 班;  对应分组的内容为:[{'class': '1 班', 'name': '小红'}]
key 为:3 班;  对应分组的内容为:[{'class': '3 班', 'name': '熊二'}]
key 为:1 班;  对应分组的内容为:[{'class': '1 班', 'name': '小明'}]
key 为:2 班;  对应分组的内容为:[{'class': '2 班', 'name': '李雷'}, {'class': '2 班', 'name': '韩梅梅'}]
key 为:3 班;  对应分组的内容为:[{'class': '3 班', 'name': '熊大'}]

Process finished with exit code 0

举例2:

from itertools import groupby

lst=[30,20,99,50,60,65,80,90,85,88]

def func(num):
    if num < 60:
        return '不及格'
    elif num <=70:
        return '及格'
    else:
        return '良好'

ite = groupby(sorted(lst), key=func)    # 用sorted() 对 lst 中元素先进行排序。

for k, item in ite:
    print(f'key 为:{k};  对应分组的内容为:{list(item)}')

运行结果为:

key 为:不及格;  对应分组的内容为:[20, 30, 50]
key 为:及格;  对应分组的内容为:[60, 65]
key 为:良好;  对应分组的内容为:[80, 85, 88, 90, 99]

Process finished with exit code 0

11、islice(iterable, start, stop[, step ])

创建一个迭代器,内容是可以看作是对 iterable 进行类似列表的切片操作。
1、当只有两个参数时,第二个位置参数就是 截止 stop 的位置。

from itertools import islice

a = range(121)
ite = islice(a,10)      # 取到索引为10的位置,不包括索引为10的元素。

print(list(ite))

运行结果为:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Process finished with exit code 0

2、当只有3个参数时,元素 就是从 第二个参数,取到第三个参数。

from itertools import islice

a = range(1,21)
ite = islice(a,5,15)    # 索引5的值是6,索引15的值是16(不包括)

print(list(ite))

运行结果为:

[6, 7, 8, 9, 10, 11, 12, 13, 14, 15]

Process finished with exit code 0

3、当有4个参数时:

from itertools import islice

a = range(1,21)
ite = islice(a,0,None,2)    # None 表示取到结尾,2 表示步长为2

print(list(ite))

运行结果:

[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]

Process finished with exit code 0

4、当 start 参数大于等于 iterable 中的元素个数时,返回一个空的迭代器。

from itertools import islice

a = range(1,21)            # 生成的最大索引值为19
ite = islice(a,20,None,2)  # 从索引值为20的位置开始取……
print(list(ite))
[]
Process finished with exit code 0

12、starmap(function, iterable)

功能和 内置函数 map() 类似,它会创建一个 迭代器,元素是 function 历遍 iterable 的返回值。只不过 starmap() 会对每个元素 再进行一次迭代,所以它会要求每个元素也是可迭代的

import itertools

a = [1,   2,   3,   4,   5,   6,  7,  8,  9, 10]
b = [10, 11, 12, 13, 14, 15]
a_2 = [(1,1), (2,2), (3,3), (4,4), (5,5), (6,6), (7,7), (8,8), (9,9),(10,10)]
a_1 = [(1,), (2,), (3,), (4,), (5,), (6,), (7,), (8,), (9,), (10,)]

# 只需要一个参数。
def func_1(x):
    return pow(x,2)

# 解包参数。
def func_jiebao(x):
    a, b = x             #  对 x 进行解包
    return a   b

# 需要两个参数。
def func_2(x,y):
    return x y

""" ======= 一、内置函数 map() 的使用 ==========="""

# 1、当调用函数 只需要1个参数时。 这个使用应该没什么问题  ^ ^
res = map(func_1, a)
print(list(res))                 # >>> [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

# 2、传入的是一个参数,但传入的这个参数是可以解包的。
res = map(func_jiebao, a_2)    
print(list(res))                # >>> [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

# 3、当调用函数 需要2个参数时,可传入两个可迭代对象,当短的迭代对象中元素迭代完后,就停止 map 了。
res = map(func_2, a, b)
print(list(res))                # >>> [11, 13, 15, 17, 19, 21]



""" ======= 二、itertools函数 starmap() 的使用 ==========="""

# 1、当调用函数 只需要1个参数时,可用 a_1,不能用 a。
#    因为  starmap() 会对每个元素 再进行一次迭代,所以它会要求每个元素也是可迭代的。
ite_1 = itertools.starmap(func_1, a_1)
print(list(ite_1))         # >>> [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

# 2、当调用函数 需要多个参数时,它会自动的对每个元素进行解包。
ite_2 = itertools.starmap(func_2, a_2)
print(list(ite_2))        # >>> [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

13、takewhile(predicate, iterable)

takewhile() 与 dropwhile() 功能刚好相反。
takewhile() 会保留 func 返回True的元素,直到遇到使 func 返回 False 的元素,迭代过程立刻停止,并丢弃这个元素及之后的所有元素。

import itertools

a = [1, 4, 6, 4, 1]

def func(i):
    if i <= 5:
        return True
    else:
        return False

ite = itertools.takewhile(func, a)
print(list(ite))      # >>> [1, 4] 

14、tee(iterable, n=2)

相当于复制 n 个 迭代器。默认n=2。

import itertools

b = ['aa', 'bb', 'cc', 'dd']

ite = itertools.tee(b,3)

for i in ite:
    print(list(i))

从下面的运行结果中,可看出 ite 包含了 三个一样的迭代器:

['aa', 'bb', 'cc', 'dd']
['aa', 'bb', 'cc', 'dd']
['aa', 'bb', 'cc', 'dd']

15、zip_longest(*iterables, fillvalue=None)

类似内置 的 zip() 函数。

import itertools
 
a = [1,   2,   3,  4,   5,   6,  7,  8,]
b = [10,  11, 12, 13,  14,  15]

z = zip(a,b)      # 按 短的 b 来合并。
print(list(z))    # >>> [(1, 10), (2, 11), (3, 12), (4, 13), (5, 14), (6, 15)]


""" 按长的 a 来 合并,b中元素不够,就用 fillvalue 填充。"""
ite_z = itertools.zip_longest(a, b, fillvalue=0)
print(list(ite_z))

# 运行结果为:
# >>> [(1, 10), (2, 11), (3, 12), (4, 13), (5, 14), (6, 15), (7, 0), (8, 0)]


ite_z = itertools.zip_longest(a, b, fillvalue=None)
print(list(ite_z))

# 运行结果为:
# >>> [(1, 10), (2, 11), (3, 12), (4, 13), (5, 14), (6, 15), (7, None), (8, None)]

排列组合迭代器:

迭代器 说明
product(*iterables, repeat=1) 用来生成 *iterables 各元素之间的不同组合。
permutations(iterable, r=None) iterable 中取出 r 个元素进行有序的排列组合。
combinations(iterable, r) 用来在 iterable 中,无放回的取出 r 个元素进行无序排列组合。
combinations_with_replacement(iterable, r) 用来在 iterable 中,有放回的取出 r 个元素进行无序排列组合。

1、product(*iterables, repeat=1)

product() 用来生成 *iterables 各元素之间的不同组合,
但各 组合中元素的顺序 是按参数的先后顺序固定的。
比如:下面代码生成的组合, 'ABCD’的元素一定在‘xy’ 之前,不可能出现在x或y之后。

它们之间的 组合数 可以这样思考:
1号箱子存放了“A、B、C、D”四个元素,
2号箱子存放了“x、y”两个元素,
先从 1号 箱随机取一个数,有 4 种取法。
再从 2号 箱随机取一个数,有 2 种取法。
所以它们的组合数为 4 x 2  = 8 种。
import itertools

ite = itertools.product('ABCD', 'xy', repeat=1)

lite = list(ite)

print(f'长度为:{len(lite)}')
print(lite)

运行结果为:

长度为:8
[('A', 'x'), ('A', 'y'), ('B', 'x'), ('B', 'y'),
 ('C', 'x'), ('C', 'y'), ('D', 'x'), ('D', 'y')]

当 repeat >= 2 时
1、product() 会先对 参数中的各个迭代器的元素进行组合,就是 repeat=1 所生成的样子,我们先给它命名为 ”初始组合“。
注:如果参数只有一个迭代器,那它的“初始组合”就是它自身各个元素。

2、按 repeat = n 中 n 的大小,对”初始组合“进行”复制“,加上”初始组合“一共n份。
3、对这 n 份”初始组合“中的元素,进行组合。
4、最终的组合数为:(参数中各迭代器元素数量的乘积)^ (repeat 值)
所以下方代码的组合数量为:4 ^ 2= 16

import itertools

ite = itertools.product('ABCD', repeat=2)

lite = list(ite)

print(f'长度为:{len(lite)}')
print(lite)

运行结果为:

长度为:16
[('A', 'A'), ('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'A'), ('B', 'B'), ('B', 'C'), ('B', 'D'), 
('C', 'A'), ('C', 'B'), ('C', 'C'), ('C', 'D'), ('D', 'A'), ('D', 'B'), ('D', 'C'), ('D', 'D')]

原理如下:
python itertools 使用详解_第2张图片
当 n = 3 时, 就会在此基础上再进行一次组合:
python itertools 使用详解_第3张图片

2、permutations(iterable, r=None)

permutations(iterable, r=None) 函数用来在 iterable 中取出 r 个元素进行排列组合,
各个排列组合中的元素有先后顺序区别,相当于
在这里插入图片描述当 r = None 时,就是对 iterable 中的所有元素进行排列。

import itertools

ite = itertools.permutations('ABCD', 2)

lite = list(ite)

print(f'长度为:{len(lite)}')
print(lite)

运行结果为:

长度为:12
[('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'A'), ('B', 'C'), ('B', 'D'), 
('C', 'A'), ('C', 'B'), ('C', 'D'), ('D', 'A'), ('D', 'B'), ('D', 'C')]

注:即使元素的值相同,不同位置的元素也被认为是不同的。如果元素值都不同,每个排列中的元素值不会重复。
如下:

import itertools

ite = itertools.permutations('ABB', 2)

lite = list(ite)

print(f'长度为:{len(lite)}')
print(lite)

运行结果为:

长度为:6
[('A', 'B'), ('A', 'B'), ('B', 'A'), ('B', 'B'), ('B', 'A'), ('B', 'B')]

3、combinations(iterable, r)

该函数用来在 iterable 中取出 r 个元素进行无序排列组合,各个排列组合中的元素无先后顺序区别。
相当于 :
在这里插入图片描述即可看成: 一个盒子里有r个不同的小球,从中一把抓出 r 个小球,看看有多少种小球的组合。
当 r = 0 时,返回一个迭代器,里面只有一个元素,且该元素为空元组 ( )
当 r > 参数中迭代器元素的数量时,返回一个空迭代器。
注:即使元素的值相同,不同位置的元素也被认为是不同的。如果元素值都不同,每个排列中的元素值不会重复,同 permutations()

import itertools

ite = itertools.combinations('ABCD', 2)

lite = list(ite)

print(f'长度为:{len(lite)}')
print(lite)

运行结果为:

长度为:6
[('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'C'), ('B', 'D'), ('C', 'D')]

4、combinations_with_replacement(iterable, r)

这个就是“可重组合”,
可看成: 先从一个盒子里先抓出一 个小球,把小球放回后,再接着抓一次,重复r次后,获得的组合。
且这个组合中的元素会被去重,即(A,B) 和 (B,A) 会被当成相同的元素,只保留一个。
当 r = 0 时,返回一个迭代器,里面只有一个元素,且该元素为()。
注:即使元素的值相同,不同位置的元素也被认为是不同的。如果元素值都不同,每个排列中的元素值不会重复。

import itertools

ite = itertools.combinations_with_replacement('ABCD', 2)

lite = list(ite)

print(f'长度为:{len(lite)}')
print(lite)

运行结果为:

长度为:10
[('A', 'A'), ('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'B'), 
('B', 'C'), ('B', 'D'), ('C', 'C'), ('C', 'D'), ('D', 'D')]

你可能感兴趣的:(python知识点整理)