python每天一个技巧——Day 4 | 使用 zip 并行迭代

我们学习 Day 4:使用 zip 并行迭代。这是处理多个序列同步操作的强劲工具

深度解析:zip()函数

1. 基础用法:同步迭代多个序列

zip() 用于将多个可迭代对象”压缩”在一起,并行迭代

names = ['Alice', 'Bob', 'Charlie']
scores = [85, 92, 78]
grades = ['A', 'A', 'B']

# 传统方法(不推荐)
for i in range(len(names)):
    print(f"{names[i]}: {scores[i]}分, 等级: {grades[i]}")

print("---")

# 使用 zip()(推荐)
for name, score, grade in zip(names, scores, grades):
    print(f"{name}: {score}分, 等级: {grade}")

输出:

Alice: 85分, 等级: A
Bob: 92分, 等级: A
Charlie: 78分, 等级: B

2.zip()的工作原理

zip() 创建一个迭代器,生成元组,其中每个元组包含来自各个可迭代对象的对应元素:

numbers = [1, 2, 3]
letters = ['a', 'b', 'c']

zipped = zip(numbers, letters)
print(list(zipped))  # 输出: [(1, 'a'), (2, 'b'), (3, 'c')]

3. 处理不同长度的序列

默认情况下,zip() 以最短的序列为准:

numbers = [1, 2, 3]
letters = ['a', 'b', 'c']

zipped = zip(numbers, letters)
print(list(zipped))  # 输出: [(1, 'a'), (2, 'b'), (3, 'c')]

3. 处理不同长度的序列

默认情况下,zip() 以最短的序列为准:

list1 = [1, 2, 3, 4, 5]
list2 = ['a', 'b', 'c']

result = list(zip(list1, list2))
print(result)  # 输出: [(1, 'a'), (2, 'b'), (3, 'c')]

4.zip_longest():处理不同长度的序列

从 itertools 模块导入,以最长的序列为准,用指定值填充空缺:

from itertools import zip_longest

list1 = [1, 2, 3, 4, 5]
list2 = ['a', 'b', 'c']

# 默认用 None 填充
result = list(zip_longest(list1, list2))
print(result)  # 输出: [(1, 'a'), (2, 'b'), (3, 'c'), (4, None), (5, None)]

# 自定义填充值
result_custom = list(zip_longest(list1, list2, fillvalue='N/A'))
print(result_custom)  # 输出: [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'N/A'), (5, 'N/A')]

5. 实际应用场景

场景1:数据配对和处理

# 学生姓名和成绩配对
students = ['Alice', 'Bob', 'Charlie']
exam_scores = [85, 92, 78]
homework_scores = [90, 88, 85]

print("学生总成绩:")
for student, exam, hw in zip(students, exam_scores, homework_scores):
    total = exam + hw
    print(f"{student}: 考试{exam} + 作业{hw} = 总分{total}")

场景2:字典键值对操作

# 合并两个列表为字典
keys = ['name', 'age', 'city']
values = ['Alice', 25, 'New York']

person_dict = dict(zip(keys, values))
print(person_dict)  # 输出: {'name': 'Alice', 'age': 25, 'city': 'New York'}

# 字典键值交换
original = {'a': 1, 'b': 2, 'c': 3}
swapped = dict(zip(original.values(), original.keys()))
print(swapped)  # 输出: {1: 'a', 2: 'b', 3: 'c'}

场景3:矩阵转置

# 使用 zip() 转置矩阵
matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

transposed = list(zip(*matrix))
print("转置前:")
for row in matrix:
    print(row)

print("转置后:")
for row in transposed:
    print(row)

6. 高级用法技巧

技巧1:与 enumerate() 结合

names = ['Alice', 'Bob', 'Charlie']
scores = [85, 92, 78]

for idx, (name, score) in enumerate(zip(names, scores), start=1):
    print(f"{idx}. {name}: {score}分")

技巧2:解压序列

# 使用 * 操作符解压
pairs = [(1, 'a'), (2, 'b'), (3, 'c')]
numbers, letters = zip(*pairs)

print(numbers)   # 输出: (1, 2, 3)
print(letters)   # 输出: ('a', 'b', 'c')

技巧3:并行排序

# 根据一个列表排序另一个列表
names = ['Charlie', 'Alice', 'Bob']
scores = [78, 85, 92]

# 先配对,再按分数排序
paired = sorted(zip(scores, names))
sorted_scores, sorted_names = zip(*paired)

print("按分数排序:")
for score, name in zip(sorted_scores, sorted_names):
    print(f"{name}: {score}分")

7.zip_longest()的实用场景

from itertools import zip_longest

# 处理不完整的数据
students = ['Alice', 'Bob', 'Charlie', 'David']
midterm_scores = [85, 92]  # 只有前两个学生的成绩
final_scores = [78, 88, 90]  # 只有前三个学生的成绩

print("成绩表(缺考标记为0):")
for student, mid, final in zip_longest(students, midterm_scores, final_scores, fillvalue=0):
    print(f"{student}: 期中{mid}, 期末{final}")

8. 实际项目案例

案例1:CSV 数据处理

def process_csv_data(headers, rows):
    """处理CSV格式数据"""
    processed_data = []
    
    for row in rows:
        # 将每行数据与表头配对
        row_dict = dict(zip(headers, row))
        processed_data.append(row_dict)
    
    return processed_data

# 模拟CSV数据
csv_headers = ['Name', 'Age', 'City']
csv_rows = [
    ['Alice', '25', 'New York'],
    ['Bob', '30', 'London'],
    ['Charlie', '22', 'Paris']
]

result = process_csv_data(csv_headers, csv_rows)
for item in result:
    print(item)

案例2:配置管理系统

def merge_configs(default_config, user_config):
    """合并默认配置和用户配置"""
    merged = {}
    
    # 确保处理所有可能的键
    all_keys = set(default_config.keys()) | set(user_config.keys())
    
    for key in all_keys:
        default_val = default_config.get(key)
        user_val = user_config.get(key)
        # 用户配置优先于默认配置
        merged[key] = user_val if user_val is not None else default_val
    
    return merged

# 使用示例
defaults = {'theme': 'dark', 'language': 'en', 'notifications': True}
user_prefs = {'language': 'zh', 'font_size': 14}

final_config = merge_configs(defaults, user_prefs)
print(final_config)

今日练习

练习1:基础应用

names = ['Alice', 'Bob', 'Charlie']
ages = [25, 30, 35]
cities = ['New York', 'London', 'Paris']

# 使用 zip() 打印每个人的完整信息
# 你的代码 here

练习2:数据处理

prices = [100, 200, 150, 300]
quantities = [2, 1, 3]

# 计算每个商品的总价,处理不同长度的情况
# 使用 zip_longest,缺货商品总价为0
from itertools import zip_longest
# 你的代码 here

练习3:实战应用

def create_report(products, prices, sales):
    """
    生成销售报告,包含产品、单价、销量、总销售额
    处理不同长度的情况,缺失数据用0填充
    """
    # 你的代码 here
    pass

# 测试
products = ['A', 'B', 'C', 'D']
prices = [10, 20, 15]
sales = [100, 50, 80, 120, 30]

print(create_report(products, prices, sales))

练习答案:

# 练习1答案:
for name, age, city in zip(names, ages, cities):
    print(f"{name}, {age}岁, 来自{city}")

# 练习2答案:
from itertools import zip_longest
total_prices = []
for price, qty in zip_longest(prices, quantities, fillvalue=0):
    total = price * qty
    total_prices.append(total)
print(total_prices)  # 输出: [200, 200, 450, 0]

# 练习3答案:
from itertools import zip_longest

def create_report(products, prices, sales):
    report = []
    for product, price, sale in zip_longest(products, prices, sales, fillvalue=0):
        revenue = price * sale
        report.append(f"{product}: 单价{price}, 销量{sale}, 销售额{revenue}")
    return "
".join(report)

今日总结

  • zip(): 并行迭代多个序列,以最短序列为准
  • zip_longest(): 以最长序列为准,可自定义填充值
  • 适用场景: 数据配对、字典操作、矩阵转置等
  • 最佳实践: 与 enumerate()、列表推导式等结合使用

记住:当你需要同步处理多个序列时,zip() 是你的首选工具!

明天我们将学习 Python 中超级优雅的特性:列表/字典/集合推导式

© 版权声明

相关文章

暂无评论

none
暂无评论...