欢迎关注 “小白玩转Python”,发现更多 “有趣”
引言
假设我们有两个列表,一个包含名字,另一个包含姓氏。我们希望以某种方式将名字与相应的姓氏组合成元组。换句话说,我们希望将来自多个具有相同索引的迭代对象的元素组合在一个元组列表中:
list_1 = [‘Jane’, ‘John’, ‘Jennifer’]
list_2 = [‘Doe’, ‘Williams’, ‘Smith’]
Desired Output:
[('Jane', 'Doe'), ('John', 'Williams'), ('Jennifer', 'Smith')]
zip() 函数
我们可以使用 zip()函数来实现这一点,这是一个内置的 Python 函数。函数之所以命名为 zip()函数,是因为它的类似机制是物理拉链。当你拉上拉链的时候,你把两边都拉在了一起。这就是 zip()函数的工作原理!它将来自多个迭代对象的相同索引的元素作为相同元组的元素放在一起。
zip(*iterables)
函数接受迭代对象作为参数,例如列表、文件、元组、集合等。函数将创建一个迭代器,从传入的每个迭代对象中聚合元素。换句话说,它将返回一个元组迭代器,其中 i-th 元组将包含传入的每个迭代器中的 i-th 元素。一旦最短的输入迭代用完,该迭代器将停止。
使用 zip() 函数
基于上述目标,我们有两个列表(这是可迭代的对象) ,我们希望将每个列表中相同的索引元素组合在一起。因此,我们可以使用 zip()函数来完成以下任务:
first_names = [‘Jane’, ‘John’, ‘Jennifer’]
last_names = [‘Doe’, ‘Williams’, ‘Smith’]
full_names = list(zip(first_names, last_names))
print(full_names)
# [('Jane', 'Doe'), ('John', 'Williams'), ('Jennifer', 'Smith')]
请记住,zip()函数返回一个迭代器。因此,我们需要使用 list()函数,它将使用这个返回的迭代器(或 zip对象)来创建列表。此外,只要传入的迭代对象是有序的(序列) ,那么元组将包含与在 zip()函数中传入的参数相同的从左到右顺序的元素。
如果我们有三个迭代对象呢?
假设我们有另外一个列表,年龄,包含了另外两个列表中相应个体的年龄,名字和姓氏。我们还想在元组中包括年龄,并且有名和姓。如上所述,zip()函数可以接受任意数量的迭代。
first_names = ['Jane', 'John', 'Jennifer']
last_names = ['Doe', 'Williams', 'Smith']
ages = [20, 40, 30]
names_and_ages = list(zip(first_names, last_names, ages))
print(names_and_ages)
# [('Jane', 'Doe', 20), ('John', 'Williams', 40), ('Jennifer', 'Smith', 30)]
请注意 names_and_ages 是如何包含带有 n 个元素的元组(参数数量相同,或者可迭代对象,我们传递给 zip()函数)。
传入一个参数到 zip()
如果我们只将一个可迭代的对象传递给 zip()函数,那么我们将得到一个包含1条目元组的列表,如下所示:
first_names = ['Jane', 'John', 'Jennifer']
print(list(zip(first_names)))
# [('Jane',), ('John',), ('Jennifer',)]
长度不等的迭代词
如果我们传入长度不等的列表(或其他可迭代对象)会怎样?换句话说,假设我们的姓氏列表比名字列表多包含1个元素。如上所述,一旦最短的输入迭代用完,zip()函数返回的迭代器就会停止。换句话说,我们的元组列表将只包含索引中的元素,这些元素出现在传递到 zip()函数的所有迭代中。因此,在较长的迭代中的其余元素将被忽略。
first_names = [‘Jane’, ‘John’, ‘Jennifer’]
last_names = [‘Doe’, ‘Williams’, ‘Smith’, 'Jones']
full_names = list(zip(first_names, last_names))
print(full_names)
# [('Jane', 'Doe'), ('John', 'Williams'), ('Jennifer', 'Smith')]
如果需要较长的迭代对象中的元素,那么我们可以使用 itertools.zip _ longest ()函数来代替 zip()函数。它将继续执行,直到用尽最长的可迭代值,并将用传入的 fillvalue 参数值(默认值为 None)替换任何缺失的值。
Iterables 的平行迭代
我们可以使用 zip()函数并行迭代多个迭代对象。因为 zip()函数返回一个迭代器,所以我们可以在 for 循环中使用这个 zip 对象(它返回的迭代器)。由于每次迭代都返回一个元组,我们可以在 for 循环中 unzip 这个元组的元素:
first_names = ['Jane', 'John', 'Jennifer']
last_names = ['Doe', 'Williams', 'Smith']
for first, last in zip(first_names, last_names):
print(first, last)
# Output:
Jane Doe
John Williams
Jennifer Smith
或者我们可以有三个迭代:
first_names = [‘Jane’, ‘John’, ‘Jennifer’]
last_names = [‘Doe’, ‘Williams’, ‘Smith’]
ages = [20, 40, 30]
for first, last, age in zip(first_names, last_names, ages):
print(f’{first} {last} is {age} years old’)
# Output:
Jane Doe is 20 years old
John Williams is 40 years old
Jennifer Smith is 30 years old
另一个并行迭代的例子:
我们有两个清单: 收入清单和成本清单。我们想再列一个表,利润,也就是收入和成本之间的差额。我们可以通过并行迭代来实现:
revenue = [30000, 50000, 70000, 90000]
cost = [10000, 15000, 20000, 30000]
profit = []
total_profit = 0
for revenue, cost in zip(revenue, cost):
profit.append(revenue — cost)
total_profit += revenue — cost
print(profit)
# [20000, 35000, 50000, 60000]
print(total_profit)
# 165000
用 Python unzipping
假设我们有以下元组列表:
first_and_last_names = [('Jane', 'Doe'), ('John', 'Williams'), ('Jennifer', 'Smith')]
我们希望将这些元组中的元素分离成两个单独的列表。好吧,既然这是拉链的反义词(把东西拉在一起) ,那就是拉链的解开(把东西拆开)。要在 Python 中进行 unzip 操作,我们可以使用 zip()函数的 unzip 操作符 * ,如下所示:
first_names, last_names = zip(*first_and_last_names)
first_names = list(first_names)
last_names = list(last_names)
print(first_names)
# ['Jane', 'John', 'Jennifer']
print(last_names)
# ['Doe', 'Williams', 'Smith']
unpacking 运算符 * 将元组的第一个和最后一个名称列表 unpack 到它的元组中。然后,这些元组将被传递给 zip()函数,该函数将接收这些单独的可迭代对象(元组) ,并将它们相同的索引元素组合成元组,形成两个单独的元组。最后,通过元组 unpack 操作,这些分隔的元组将被分配给名字和姓氏变量。然后,我们使用 list()函数将这些元组转换为列表。
总结
在本教程中,我们了解了 zip()函数在 Python 中是如何工作的。我们了解了 zip()函数在不同场景中的操作方式,比如使用一个迭代或者使用长度不等的迭代。然后,我们看到了如何使用 zip()函数并行迭代多个迭代对象。最后,我们学习了如何使用解压缩操作符 * 来解压 Python 中的对象。
· END ·
HAPPY LIFE