序列5:序列方法实操下

本文详细介绍了Python中序列方法的使用,包括zip()函数的不同用法,如何利用zip(*[iter(s)]*n)切割序列,map()函数对可迭代对象进行运算,filter()函数筛选元素,以及iter()和next()函数在迭代中的作用。通过实例展示了这些方法的实际应用。

目录

12. zip()

12.1 zip(*[iter(s)]*n) 

12.2 zip() 函数与 * 运算符

13. map()

14. filter()

14. iter()

15. next()


12. zip()

zip()函数用于创建一个聚合多个可迭代对象的迭代器; 

做法是将作为参数传入的每个可迭代对象的每个元素依次组合成元组,即第 i 个元组包含来自每个参数的第 i 个元素;

可通过list()、tuple()将enumerate()返回的迭代器转换为列表、元组;

支持列表、元组、字符串、range()等可迭代对象混合进行聚合,支持1个或多个可迭代对象聚合;

当多个可迭代对象元素数不一致时,以元素数最少的可迭代对象为准,取相应轮次元素组成迭代器;

可以使用itertools函数模块的itertools.zip_longest()函数,按元素数最多的可迭代对象组成迭代器,空出元素填充None。

#zip()函数用于创建一个聚合多个可迭代对象的迭代器;
zip([1,2,3],[4,5,6])
<zip object at 0x000002690CC9BB00>
list(zip([1,2,3],[4,5,6]))
[(1, 4), (2, 5), (3, 6)]

#支持列表、元组、字符串、range()等可迭代对象混合进行聚合,支持1个或多个可迭代对象聚合
list(zip([1,2,3]))
[(1,), (2,), (3,)]
tuple(zip([1,2,3],(4,5,6),'789',range(3)))
((1, 4, '7', 0), (2, 5, '8', 1), (3, 6, '9', 2))

#当多个可迭代对象元素数不一致时,以元素数最少的可迭代对象为准,取相应轮次元素组成迭代器
list(zip([1,2],(3,4,5),'6789'))
[(1, 3, '6'), (2, 4, '7')]

#可以使用itertools函数模块的itertools.zip_longest()函数,按元素数最多的可迭代对象组成迭代器,空出元素填充None
import itertools
list(itertools.zip_longest([1,2],(3,4,5),'6789'))
[(1, 3, '6'), (2, 4, '7'), (None, 5, '8'), (None, None, '9')]

12.1 zip(*[iter(s)]*n) 

zip() 函数将确保可迭代对象按从左至右的顺序组合,通过 zip(*[iter(s)]*n) 的惯用形式,将同一个迭代器重复迭代 N 遍,实现将对象划分为 N 个长度块的效果;

当可迭代对象s长度不是N的整数倍时,多出部分丢弃。

举例如下:

问题:请使用一句代码,将 [1, 2, 3, 4, 5, 6, 7, 8, 9] 变成 [(1, 2, 3), (4, 5, 6), (7, 8, 9)]

>>> list(zip(*[iter([1, 2, 3, 4, 5, 6, 7, 8, 9])] * 3))
[(1, 2, 3), (4, 5, 6), (7, 8, 9)] 

解析如下:

翻开 Python Docs 文档,检索 zip() 内置函数的官方档案:

The left-to-right evaluation order of the iterables is guaranteed. This makes possible an idiom for clustering a data series into n-length groups using zip(*[iter(s)]*n). This repeats the same iterator n times so that each output tuple has the result of n calls to the iterator. This has the effect of dividing the input into n-length chunks.

官方给出答案:将同一个迭代器重复迭代 N 遍,这样可以实现将对象划分为 N 个长度块的效果。

这背后的核心逻辑是:迭代器中每迭代一个元素出来,容器里就少了一个元素!所以,这里先使用 iter() 内置函数将序列对象转化为一个迭代器。如下代码转换:

>>> x = iter([1,2,3,4,5,6,7,8,9])
>>> list(zip(x, x, x))

成功实现后,怎么封装成一句代码呢?先要把它拷贝 N 遍,所以是:[iter(s)] * n

不过 zip() 的参数是多个可迭代对象,因此我们还要将参数进行解包:zip(*[iter(s)]*n),搞定!

爬取到 A、B、C、D、E、F 六类数据依次存放在列表中,即:

[a1, b1, c1, d1, e1, f1, a2, b2, c2, d2, e2, f2, a3, b3, c3, d3, e3, f3, ...]

需要我们将其拆分成 A、B、C、D、E、F 六个不同的列表,这时这个小技巧就用得上了!

def grouped(s, n):
    "将列表分成n片一组"
    "s -> (s0,s1,s2,...sn-1), (sn,sn+1,sn+2,...s2n-1), (s2n,s2n+1,s2n+2,...s3n-1), ..."
    return zip(*[iter(s)] * n)

实操如下:

s = [1,2,3,4,5,6,7,8,9,10,11,12]
s2 = list(zip(*[iter(s)]*4))
s2
[(1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)]
s2 = list(zip(*[iter(s)]*6))
s2

s = 'abcdefghijklmn'
s2 = list(zip(*[iter(s)]*3))
s2
[('a', 'b', 'c'), ('d', 'e', 'f'), ('g', 'h', 'i'), ('j', 'k', 'l')]

s = (0,1,2,3,4,5,6)
s2 = list(zip(*[iter(s)]*2))
s2
[(0, 1), (2, 3), (4, 5)]

12.2 zip() 函数与 * 运算符

结合上文的核心逻辑:迭代器中每迭代一个元素出来,容器里就少了一个元素!,zip() 函数与 * 运算符相结合可以用来拆解一个列表,zip(*[s1,s2,s3,……])等效于zip(s1,s2,s3,……)。

举例如下:

>>> x = [1, 2, 3]
>>> y = [4, 5, 6]
>>> x2, y2 = zip(*zip(x, y))
>>> x == list(x2) and y == list(y2)
True

[1, 2, 3] 和 [4, 5, 6] 通过 zip() 函数压缩完 zipped 变量中包含的组合是 (1, 4), (2, 5), (3, 6)

因此,zip(*zip(x, y)) 参数解包之后,变成 zip((1, 4), (2, 5), (3, 6))

重新 zip() 后包含的组合便是 (1, 2, 3), (4, 5, 6)

实操如下:

list(zip(*[[1,2,3],[4,5,6],[7,8,9]]))
[(1, 4, 7), (2, 5, 8), (3, 6, 9)]
list(zip([1,2,3],[4,5,6],[7,8,9]))
[(1, 4, 7), (2, 5, 8), (3, 6, 9)]

list(zip(*('abc','def','hij')))
[('a', 'd', 'h'), ('b', 'e', 'i'), ('c', 'f', 'j')]
list(zip('abc','def','hij'))
[('a', 'd', 'h'), ('b', 'e', 'i'), ('c', 'f', 'j')]

13. map()

map() 函数会根据提供的函数对指定的可迭代对象的每个元素进行运算,并将返回运算结果以迭代器的形式返回;可通过list()、tuple()将enumerate()返回的迭代器转换为列表、元组;

如果传入了多个可迭代对象,那么指定的函数也必须能够支持相同个数的参数; 

当有多个可迭代对象时,最短的可迭代对象终止时,则整个迭代过程跟着结束;  

对于函数的输入已经是参数元组的情况(数据已被“预组对”),可以使用itertools.starmap() 函数来替代。

#pow函数支持两个参数,则需要引入两个可迭代对象,否则报错
list(map(pow,[9,10,12],[4,5,6]))
[6561, 100000, 2985984]
list(map(pow,[9,10,12]))
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: pow() missing required argument 'exp' (pos 2)

#divmod支持两个参数,需要引入两个可迭代对象,两个迭代对象元素数不一致时,以元素少的为准
list(map(divmod,[9,10,11,12,13],[4,5,6]))
[(2, 1), (2, 0), (1, 5)]

#abs函数支持1个参数,则只需要1个可迭代对象,否则报错
list(map(abs,[9,10,12],[4,5,6]))
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: abs() takes exactly one argument (2 given)
list(map(abs,[-9,1+2j,3.3]))
[9, 2.23606797749979, 3.3]

#对于需要引入多个参数的函数,如参与计算的参数已被“预组队”,使用itertools.starmap() 函数
list(map(divmod,[9,10,11],[4,5,6]))
[(2, 1), (2, 0), (1, 5)]
import itertools
list(itertools.starmap(divmod,[(9,4),(10,5),(11,6)]))
[(2, 1), (2, 0), (1, 5)]

14. filter()

filter() 函数会根据提供的函数对指定的可迭代对象的每个元素进行运算,并将运算结果为真的元素,以迭代器的形式返回(注意:返回的是元素本身);

如果提供的函数是 None,则会假设它是一个 “鉴真” 函数,即可迭代对象中所有值为假的元素会被移除;

请注意,filter(function, iterable) 相当于以下两个生成器表达式:  

  • 当 function 参数不是 None 的时候相当于 (item for item in iterable if function(item));
  • 当 function 是 None 的时候为 (item for item in iterable if item)。  
list(filter(None,[0,[],(),'',' ',0.0,'0',0+0j,]))
[' ', '0']
list(filter(abs,[0,1,2,0.0,0+0j,]))
[1, 2]
list(filter(str.isdecimal,'a1<3V7=0cdE'))
['1', '3', '7', '0']

14. iter()

iter() 函数将返回一个迭代器对象。  

s = [1,2,3,4,5]
s1 = iter(s)
s1
<list_iterator object at 0x000002690CCBC580>

15. next()

next() 函数将获取迭代器的下一个元素。  

可选参数default,指定当迭代器的最后一个元素取出之后,显示的内容;如果不指定该参数则抛出 StopIteration 异常。

#next() 函数将获取迭代器的下一个元素  
s = [0,'abc',1.22,range(5),[1+3j]]
t = iter(s)

next(t)
0
next(t)
'abc'
next(t)
1.22
next(t)
range(0, 5)
next(t)
[(1+3j)]

#可选参数default,指定当迭代器的最后一个元素取出之后,显示的内容
#如果不指定该参数则抛出 StopIteration 异常
next(t)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
StopIteration
next(t,'abc')
'abc'
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

燃烧的火鸟啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值