Python之zip函数详解

Python之zip函数详解


zip() 函数是 Python 内置函数之一,它可以将多个序列(列表、元组、字典、集合、字符串以及 range() 区间构成的列表)“压缩”成一个 zip 对象。所谓“压缩”,其实就是将这些序列中对应位置的元素重新组合,生成一个个新的元组。

和 Python 3.x 版本不同,Python 2.x 版本中的 zip() 函数会直接返回列表,而不是返回 zip 对象。但是,返回的列表或者 zip 对象,其包含的元素(都是元组)是相同的。

1. zip() 函数的语法格式为:

zip(iterable, ...)

其中 iterable,… 表示多个列表、元组、字典、集合、字符串,甚至还可以为 range() 区间。

2. 了解zip函数基础语法

zip函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的iterator

举例如下,我们可以使用它以如下方式来组合两个列表,样例代码如下:

id = [1, 2, 3, 4]
leaders = ['Elon Mask', 'Tim Cook', 'Bill Gates', 'Bai Li']
record = zip(id, leaders)

print(record)
# <zip object at 0x7f266a707d80>

print(list(record))
# [(1, 'Elon Mask'), (2, 'Tim Cook'), (3, 'Bill Gates'), (4, 'Bai Li')]

如上面的示例所示,zip函数返回一个元组迭代器,其中第i 个元组包含每个列表中的第i 个元素。

3. zip函数同时处理多个对象

事实上,Python中的zip函数具有强大的功能,比如它可以一次处理任意数量的可迭代项,而不仅仅是两个。

首先,我们来看如果我们将一个list 传递给 zip 函数,样例如下:

id = [1, 2, 3, 4]
record = zip(id)
print(list(record))
# [(1,), (2,), (3,), (4,)]

如果我们同时传递三个list ,结果如下:

id = [1, 2, 3, 4]
leaders = ['Elon Mask', 'Tim Cook', 'Bill Gates', 'Bai Li']
sex = ['m', 'm', 'm', 'm']
record = zip(id, leaders, sex)

print(list(record))
# [(1, 'Elon Mask', 'm'), (2, 'Tim Cook', 'm'), (3, 'Bill Gates', 'm'), (4, 'Bai Li', 'm')]

如上所述,无论我们传递给zip函数多少个可迭代项,它都能按照我们的预期来正常工作。

顺便说一下,如果没有参数,zip 函数只返回一个空的迭代器。

4. zip函数处理长度不等的参数

真实数据并不总是干净和完整的,有时我们必须处理不等长的可迭代数据。默认情况下,zip函数的结果基于最短的可迭代项。

举例如下:

id = [1, 2]
leaders = ['Elon Mask', 'Tim Cook', 'Bill Gates', 'Bai Li']
record = zip(id, leaders)

print(list(record))
# [(1, 'Elon Mask'), (2, 'Tim Cook')]

如上面的代码所示,最短的列表是id ,因此record 只包含两个元组,并且忽略了列表leaders 中的最后两个元素。

如果最后两位leader 因被忽视而不高兴,我们该怎么办?

Python将再次帮助我们。itertools 模块中还有一个名为zip_langest 的函数。顾名思义,它是zip函数的兄弟,其结果基于最长的参数。

我们不妨使用zip_langest 函数来生成上述record列表,结果如下:

from itertools import zip_longest
id = [1, 2]
leaders = ['Elon Mask', 'Tim Cook', 'Bill Gates', 'Bai Li']

long_record = zip_longest(id, leaders)
print(list(long_record))
# [(1, 'Elon Mask'), (2, 'Tim Cook'), (None, 'Bill Gates'), (None, 'Bai Li')]

long_record_2 = zip_longest(id, leaders, fillvalue='Top')
print(list(long_record_2))
# [(1, 'Elon Mask'), (2, 'Tim Cook'), ('Top', 'Bill Gates'), ('Top', 'Bai Li')]

如上所述,zip_langest 函数基于其最长参数来返回结果。可选的fillvalue 参数(默认值为None)可以帮助我们填充缺失的值。

5. unzip操作

在上一个示例中,如果我们首先获得列表record ,那么我们如何将其unzip 解压缩为单独的可迭代项?

不幸的是,Python并没有直接的解压缩unzip函数。然而,如果我们熟悉星号* 的技巧,解压缩将是一项非常简单的任务。

record = [(1, 'Elon Mask'), (2, 'Tim Cook'), (3, 'Bill Gates'), (4, 'Bai Li')]
id, leaders = zip(*record)
print(id)
# (1, 2, 3, 4)
print(leaders)
# ('Elon Mask', 'Tim Cook', 'Bill Gates', 'Bai Li')

在上面的示例中,星号执行了拆包操作,即从记录列表中拆包所有四个元组。

6. 通过zip函数创建和更新dict

受益于功能强大的zip 函数,基于一些独立的列表来创建和更新dict 将非常方便。

我们可以使用以下one-line的方案:

● 使用字典生成式和zip函数

● 使用dictzip 函数

样例代码如下:

id = [1, 2, 3, 4]
leaders = ['Elon Mask', 'Tim Cook', 'Bill Gates', 'Bai Li']

# create dict by dict comprehension
leader_dict = {i: name for i, name in zip(id, leaders)}
print(leader_dict)
# {1: 'Elon Mask', 2: 'Tim Cook', 3: 'Bill Gates', 4:'Bai Li'}

# create dict by dict function
leader_dict_2 = dict(zip(id, leaders))
print(leader_dict_2)
# {1: 'Elon Mask', 2: 'Tim Cook', 3: 'Bill Gates', 4: 'Bai Li'}

# update
other_id = [5, 6]
other_leaders = ['Larry Page', 'Sergey Brin']
leader_dict.update(zip(other_id, other_leaders))
print(leader_dict)
# {1: 'Elon Mask', 2: 'Tim Cook', 3: 'Bill Gates', 4: ''Bai Li'', 5: 'Larry Page', 6: 'Sergey Brin'}

上面的示例根本不使用for 循环 , 这是多么的优雅和Pythonic

7. 在for循环中使用zip函数

同时处理多个可迭代项通常是常见的场景, 此时我们可以在for循环中配合使用函数zip ,这也是我最喜欢函数zip 的用法之一。

举例如下:

products = ["cherry", "strawberry", "banana"]
price = [2.5, 3, 5]
cost = [1, 1.5, 2]
for prod, p, c in zip(products, price, cost):
    print(f'The profit of a box of {prod} is £{p-c}!')
# The profit of a box of cherry is £1.5!
# The profit of a box of strawberry is £1.5!
# The profit of a box of banana is £3!

8. 实现矩阵转置

我们来看以下问题:

如何优雅地实现矩阵的转置操作?

鉴于在上文中我们已经介绍了函数zip ,星号*,以及列表生成式,所以one-line的实现方式如下:

matrix = [[1, 2, 3], [1, 2, 3]]
matrix_T = [list(i) for i in zip(*matrix)]
print(matrix_T)
# [[1, 1], [2, 2], [3, 3]]

9. zip() 函数的基本用法:

my_list = [11,12,13]
my_tuple = (21,22,23)
print([x for x in zip(my_list,my_tuple)])
my_dic = {31:2,32:4,33:5}
my_set = {41,42,43,44}
print([x for x in zip(my_dic)])
my_pychar = "python"
my_shechar = "shell"
print([x for x in zip(my_pychar,my_shechar)])

程序执行结果为:

[(11, 21), (12, 22), (13, 23)]
[(31,), (32,), (33,)]
[('p', 's'), ('y', 'h'), ('t', 'e'), ('h', 'l'), ('o', 'l')]

如果读者分析以上的程序和相应的输出结果不难发现,在使用 zip() 函数“压缩”多个序列时,它会分别取各序列中第 1 个元素、第 2 个元素、… 第 n 个元素,各自组成新的元组。需要注意的是,当多个序列中元素个数不一致时,会以最短的序列为准进行压缩。

另外,对于 zip() 函数返回的 zip 对象,既可以像上面程序那样,通过遍历提取其存储的元组,也可以向下面程序这样,通过调用 list() 函数将 zip() 对象强制转换成列表:

my_list = [11,12,13]
my_tuple = (21,22,23)
print(list(zip(my_list,my_tuple)))

程序执行结果为:

[(11, 21), (12, 22), (13, 23)]

10. 参数iterable为可迭代的对象,并且可以有多个参数

该函数返回一个以元组为元素的列表,其中第 i 个元组包含每个参数序列的第 i 个元素。返回的列表长度被截断为最短的参数序列的长度。只有一个序列参数时,它返回一个1元组的列表。没有参数时,它返回一个空的列表。

import numpy as np
a=[1,2,3,4,5]
b=(1,2,3,4,5)
c=np.arange(5)
d="zhang"
zz=zip(a,b,c,d)
print(zz)

输出:

[(1, 1, 0, 'z'), (2, 2, 1, 'h'), (3, 3, 2, 'a'), (4, 4, 3, 'n'), (5, 5, 4, 'g')]

11. 当没有参数的时候

import numpy as np
zz=zip()
print(zz)

输出:

[]

12. 当只有一个参数的时候

import numpy as np
a=[1,2,3]
zz=zip(a)
print(zz)

输出:

[(1,), (2,), (3,)]

13. 当多个参数长度不同的时候

import numpy as np
a=[1,2,3]
b=[1,2,3,4]
c=[1,2,3,4,5]
zz=zip(a,b,c)
print(zz)

输出:

[(1, 1, 1), (2, 2, 2), (3, 3, 3)]

14. zip() 和 * 操作符一起操作可以用来 unzip 一个列表

看下面的代码:

import numpy as np
a=[1,2,3]
b=[4,5,6]
c=[7,8,9]
zz=zip(a,b,c)
print(zz)

x,y,z=zip(*zz)
print(x)
print(y)
print(z)

输出:

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

注意这里输出的每个都是元组,而不一定是原来的类型,但是值不会发生变化(除非原来的参数列表长度不一样,看下面的代码)

import numpy as np
a=[1,2,3]
b=[4,5,6,7]
c=[8,9,10,11,12]
zz=zip(a,b,c)
print(zz)

x,y,z=zip(*zz)
print(x)
print(y)
print(z)

输出:

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

unzip后的列表b和c的值都少了。

15. 用zip生成字典

要将长度相同的列表合成字典,您需要使用Python中的zip()函数和字典推导式。

例如,如果您有两个列表,一个是键列表,另一个是值列表,您可以这样合成它们:

keys = ['a', 'b', 'c']
values = [1, 2, 3]

dictionary = {key: value for key, value in zip(keys, values)}
print(dictionary)  # 输出:{'a': 1, 'b': 2, 'c': 3}

在这个例子中,zip(keys, values)函数将两个列表中的对应元素打包成元组,然后通过字典推导式将它们转换成字典。

如果您的键列表和值列表的长度不同,zip()函数将只返回长度等于最短列表的元组。如果您想要将长度不同的列表合并为字典,您可以使用itertools.zip_longest()函数,该函数会填充缺失值。例如:

keys = ['a', 'b', 'c']
values = [1, 2]
dictionary = {key: value for key, value in itertools.zip_longest(keys, values)}
print(dictionary)  # 输出:{'a': 1, 'b': 2, 'c': None}

在这个例子中,zip_longest(keys, values)函数将两个列表中的对应元素打包成元组,然后通过字典推导式将它们转换成字典。由于值列表比键列表短,因此缺失的值将被填充为None。

《AUTOSAR谱系分解(ETAS工具链)》之总目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值