Python(二十六) 嵌套推导式与条件筛选详解
1. 什么是嵌套推导式
在学习 Python 推导式时,我们通常先接触最简单的写法。
例如,生成一个平方列表:
nums = [x * x for x in range(1, 6)]
print(nums)
输出:
[1, 4, 9, 16, 25]
这种写法只有一个 for,比较简单。
如果推导式中出现多个 for,就可以称为嵌套推导式。
例如:
result = [(x, y) for x in [1, 2] for y in [3, 4]]
print(result)
输出:
[(1, 3), (1, 4), (2, 3), (2, 4)]
它等价于下面的普通嵌套循环:
result = []
for x in [1, 2]:
for y in [3, 4]:
result.append((x, y))
print(result)
通俗理解:
嵌套推导式就是把嵌套 for 循环写进推导式里。
2. 什么是条件筛选
条件筛选就是在推导式中加上 if,只保留符合条件的数据。
例如,筛选偶数:
nums = [1, 2, 3, 4, 5, 6]
evens = [x for x in nums if x % 2 == 0]
print(evens)
输出:
[2, 4, 6]
它等价于:
nums = [1, 2, 3, 4, 5, 6]
evens = []
for x in nums:
if x % 2 == 0:
evens.append(x)
print(evens)
通俗理解:
条件筛选就是先遍历,再判断,符合条件才放进去。
3. 本节学习目标
学完这篇内容,应该能够掌握:
- 嵌套推导式的基本写法。
- 多个
for的执行顺序。 - 条件筛选
if的写法。 if...else在推导式中的写法。- 二维列表的展平、筛选和转换。
- 嵌套列表推导式、字典推导式、集合推导式。
- 什么时候适合用推导式,什么时候不适合用。
4. 先复习普通推导式
4.1 列表推导式
基本语法:
[表达式 for 变量 in 可迭代对象]
示例:
nums = [x for x in range(5)]
print(nums)
输出:
[0, 1, 2, 3, 4]
4.2 带条件的列表推导式
基本语法:
[表达式 for 变量 in 可迭代对象 if 条件]
示例:
nums = [x for x in range(10) if x % 2 == 0]
print(nums)
输出:
[0, 2, 4, 6, 8]
4.3 字典推导式
基本语法:
{键表达式: 值表达式 for 变量 in 可迭代对象}
示例:
squares = {x: x * x for x in range(1, 6)}
print(squares)
输出:
{1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
4.4 集合推导式
基本语法:
{表达式 for 变量 in 可迭代对象}
示例:
chars = {ch for ch in "banana"}
print(chars)
输出可能是:
{'b', 'a', 'n'}
集合会自动去重,并且没有固定顺序。
5. 嵌套推导式的基本语法
嵌套列表推导式的常见写法:
[表达式 for 外层变量 in 外层可迭代对象 for 内层变量 in 内层可迭代对象]
例如:
result = [(x, y) for x in [1, 2] for y in [3, 4]]
print(result)
输出:
[(1, 3), (1, 4), (2, 3), (2, 4)]
等价于:
result = []
for x in [1, 2]:
for y in [3, 4]:
result.append((x, y))
print(result)
记忆方式:
推导式中 for 的顺序,和普通嵌套 for 循环的顺序一致。
也就是说:
[(x, y) for x in a for y in b]
对应:
for x in a:
for y in b:
...
6. 嵌套推导式的执行顺序
很多初学者看见嵌套推导式会不知道从哪里开始读。
建议从第一个 for 开始读。
示例:
result = [(x, y) for x in [1, 2] for y in [3, 4]]
阅读顺序:
1. x 先取 1。
2. y 再依次取 3、4。
3. 得到 (1, 3)、(1, 4)。
4. x 再取 2。
5. y 再依次取 3、4。
6. 得到 (2, 3)、(2, 4)。
最终结果:
[(1, 3), (1, 4), (2, 3), (2, 4)]
可以把它想象成:
外层循环走一步,内层循环跑一整圈。
7. 生成所有组合
嵌套推导式最常见的用途之一,就是生成所有组合。
7.1 商品颜色和尺码组合
colors = ["红色", "蓝色"]
sizes = ["S", "M", "L"]
products = [(color, size) for color in colors for size in sizes]
print(products)
输出:
[('红色', 'S'), ('红色', 'M'), ('红色', 'L'), ('蓝色', 'S'), ('蓝色', 'M'), ('蓝色', 'L')]
等价于:
colors = ["红色", "蓝色"]
sizes = ["S", "M", "L"]
products = []
for color in colors:
for size in sizes:
products.append((color, size))
print(products)
7.2 坐标点组合
生成一个简单的坐标网格:
points = [(x, y) for x in range(3) for y in range(2)]
print(points)
输出:
[(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]
可以理解为:
x 有 0、1、2 三种选择。
y 有 0、1 两种选择。
总共有 3 * 2 = 6 个坐标点。
7.3 九九乘法表数据
生成九九乘法表中的表达式:
items = [f"{j}x{i}={i * j}" for i in range(1, 10) for j in range(1, i + 1)]
print(items)
输出前几个结果:
['1x1=1', '1x2=2', '2x2=4', '1x3=3', '2x3=6', '3x3=9', ...]
如果要真正打印成表格,普通循环更直观:
for i in range(1, 10):
for j in range(1, i + 1):
print(f"{j}x{i}={i * j}", end="\t")
print()
教学建议:
生成数据可以用推导式。
控制输出格式更适合用普通循环。
8. 二维列表展平
二维列表是列表里面还有列表。
例如:
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
如果想把它变成一维列表:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
可以使用嵌套推导式。
8.1 展平二维列表
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
result = [num for row in matrix for num in row]
print(result)
输出:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
等价于:
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
result = []
for row in matrix:
for num in row:
result.append(num)
print(result)
阅读方式:
先从 matrix 中取出一行 row,
再从 row 中取出每个 num,
最后把 num 放入新列表。
8.2 展平并筛选偶数
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
evens = [num for row in matrix for num in row if num % 2 == 0]
print(evens)
输出:
[2, 4, 6, 8]
等价于:
evens = []
for row in matrix:
for num in row:
if num % 2 == 0:
evens.append(num)
print(evens)
8.3 展平并转换数据
把二维列表中的所有数字扩大 10 倍:
matrix = [
[1, 2],
[3, 4]
]
result = [num * 10 for row in matrix for num in row]
print(result)
输出:
[10, 20, 30, 40]
8.4 展平字符串列表
words = ["hi", "abc"]
chars = [ch for word in words for ch in word]
print(chars)
输出:
['h', 'i', 'a', 'b', 'c']
等价于:
chars = []
for word in words:
for ch in word:
chars.append(ch)
print(chars)
9. 嵌套推导式中的条件筛选
嵌套推导式可以配合 if 条件。
语法:
[表达式 for 外层变量 in 外层对象 for 内层变量 in 内层对象 if 条件]
9.1 筛选符合条件的组合
生成两个列表中和大于 6 的组合:
a = [1, 2, 3, 4]
b = [3, 4, 5]
result = [(x, y) for x in a for y in b if x + y > 6]
print(result)
输出:
[(2, 5), (3, 4), (3, 5), (4, 3), (4, 4), (4, 5)]
等价于:
result = []
for x in a:
for y in b:
if x + y > 6:
result.append((x, y))
print(result)
9.2 筛选乘积为偶数的组合
a = [1, 2, 3]
b = [4, 5, 6]
result = [(x, y) for x in a for y in b if (x * y) % 2 == 0]
print(result)
输出:
[(1, 4), (1, 6), (2, 4), (2, 5), (2, 6), (3, 4), (3, 6)]
9.3 多个条件筛选
筛选出 x < y 且 x + y 是偶数的组合:
nums = [1, 2, 3, 4]
result = [(x, y) for x in nums for y in nums if x < y and (x + y) % 2 == 0]
print(result)
输出:
[(1, 3), (2, 4)]
也可以写成多个 if:
nums = [1, 2, 3, 4]
result = [(x, y) for x in nums for y in nums if x < y if (x + y) % 2 == 0]
print(result)
输出:
[(1, 3), (2, 4)]
教学建议:
多个条件一般用 and 写在一个 if 中,更容易读。
10. 外层条件和内层条件
嵌套推导式中,if 放在不同位置,含义可能不同。
10.1 条件放在最后
result = [(x, y) for x in range(3) for y in range(3) if x != y]
print(result)
输出:
[(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]
这个 if x != y 是在内层循环后判断的。
等价于:
result = []
for x in range(3):
for y in range(3):
if x != y:
result.append((x, y))
10.2 条件紧跟在外层 for 后面
result = [(x, y) for x in range(5) if x % 2 == 0 for y in range(3)]
print(result)
输出:
[(0, 0), (0, 1), (0, 2), (2, 0), (2, 1), (2, 2), (4, 0), (4, 1), (4, 2)]
等价于:
result = []
for x in range(5):
if x % 2 == 0:
for y in range(3):
result.append((x, y))
意思是:
先筛选外层的 x。
只有 x 是偶数时,才执行内层 y 循环。
10.3 条件位置对结果的影响
看两个例子。
例子一:
result = [(x, y) for x in range(4) if x % 2 == 0 for y in range(3)]
print(result)
输出:
[(0, 0), (0, 1), (0, 2), (2, 0), (2, 1), (2, 2)]
例子二:
result = [(x, y) for x in range(4) for y in range(3) if y % 2 == 0]
print(result)
输出:
[(0, 0), (0, 2), (1, 0), (1, 2), (2, 0), (2, 2), (3, 0), (3, 2)]
第一个例子筛选的是 x。
第二个例子筛选的是 y。
教学总结:
if 放在哪个 for 后面,通常就和哪个循环层级关系更近。
不过如果写法太绕,建议改成普通循环。
11. if 筛选和 if...else 转换
这是推导式中最容易混淆的知识点。
11.1 if 筛选
语法:
[表达式 for 变量 in 可迭代对象 if 条件]
作用:
只保留满足条件的数据。
示例:
nums = [-2, -1, 0, 1, 2]
result = [x for x in nums if x > 0]
print(result)
输出:
[1, 2]
结果数量变少了。
11.2 if...else 转换
语法:
[值1 if 条件 else 值2 for 变量 in 可迭代对象]
作用:
每个数据都处理,只是根据条件决定处理结果。
示例:
nums = [-2, -1, 0, 1, 2]
result = [x if x > 0 else 0 for x in nums]
print(result)
输出:
[0, 0, 0, 1, 2]
结果数量没有变。
11.3 两种写法对比
nums = [-2, -1, 0, 1, 2]
result1 = [x for x in nums if x > 0]
result2 = [x if x > 0 else 0 for x in nums]
print(result1)
print(result2)
输出:
[1, 2]
[0, 0, 0, 1, 2]
对比表:
| 写法 | 含义 | 结果数量 |
|---|---|---|
[x for x in nums if 条件] |
筛选数据 | 可能变少 |
[值1 if 条件 else 值2 for x in nums] |
转换数据 | 通常不变 |
12. 嵌套推导式中的 if...else
if...else 可以出现在嵌套推导式的表达式位置。
12.1 标记坐标是否在对角线上
result = ["对角线" if x == y else "普通点" for x in range(3) for y in range(3)]
print(result)
输出:
['对角线', '普通点', '普通点', '普通点', '对角线', '普通点', '普通点', '普通点', '对角线']
如果希望看得更清楚,可以保留坐标:
result = [((x, y), "对角线" if x == y else "普通点") for x in range(3) for y in range(3)]
print(result)
输出:
[((0, 0), '对角线'), ((0, 1), '普通点'), ((0, 2), '普通点'), ((1, 0), '普通点'), ((1, 1), '对角线'), ((1, 2), '普通点'), ((2, 0), '普通点'), ((2, 1), '普通点'), ((2, 2), '对角线')]
12.2 把二维列表中的奇数改成 0
matrix = [
[1, 2, 3],
[4, 5, 6]
]
result = [num if num % 2 == 0 else 0 for row in matrix for num in row]
print(result)
输出:
[0, 2, 0, 4, 0, 6]
12.3 同时使用 if...else 和筛选 if
可以同时使用 if...else 和后置 if。
例如:
nums = [-3, -2, -1, 0, 1, 2, 3]
result = ["正数" if x > 0 else "负数" for x in nums if x != 0]
print(result)
输出:
['负数', '负数', '负数', '正数', '正数', '正数']
阅读顺序:
1. for x in nums 取出每个 x。
2. if x != 0 先过滤掉 0。
3. "正数" if x > 0 else "负数" 对剩余数据分类。
这类写法对初学者有一定难度,教学时建议先拆成普通循环。
等价写法:
nums = [-3, -2, -1, 0, 1, 2, 3]
result = []
for x in nums:
if x != 0:
if x > 0:
result.append("正数")
else:
result.append("负数")
print(result)
13. 嵌套列表推导式生成二维列表
前面讲的是把二维列表变成一维列表。
现在看反过来的情况:生成二维列表。
13.1 生成 3 行 4 列的二维列表
matrix = [[0 for col in range(4)] for row in range(3)]
print(matrix)
输出:
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
这个推导式要这样读:
外层 for row in range(3) 控制生成 3 行。
内层 [0 for col in range(4)] 控制每一行有 4 个 0。
等价于:
matrix = []
for row in range(3):
line = []
for col in range(4):
line.append(0)
matrix.append(line)
print(matrix)
13.2 生成带行列值的二维列表
matrix = [[row * 10 + col for col in range(4)] for row in range(3)]
print(matrix)
输出:
[[0, 1, 2, 3], [10, 11, 12, 13], [20, 21, 22, 23]]
13.3 生成乘法表数据
table = [[i * j for j in range(1, 6)] for i in range(1, 6)]
print(table)
输出:
[[1, 2, 3, 4, 5], [2, 4, 6, 8, 10], [3, 6, 9, 12, 15], [4, 8, 12, 16, 20], [5, 10, 15, 20, 25]]
每一行可以理解为一个数字对应的乘法结果。
14. 生成二维列表的常见坑
在 Python 中,生成二维列表有一个非常经典的坑。
14.1 不推荐的写法
matrix = [[0] * 3] * 4
print(matrix)
输出:
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
看起来没问题。
但是如果修改其中一个元素:
matrix[0][0] = 1
print(matrix)
输出:
[[1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0]]
问题出现了:每一行的第一个元素都变成了 1。
原因是:
[[0] * 3] * 4 复制的是同一个小列表的引用。
多行看起来不同,实际上指向同一个列表。
14.2 推荐的写法
使用嵌套列表推导式:
matrix = [[0 for col in range(3)] for row in range(4)]
matrix[0][0] = 1
print(matrix)
输出:
[[1, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
这样每一行都是独立的列表。
教学记忆:
创建二维列表,推荐使用嵌套列表推导式。
不要简单使用 [[0] * 列数] * 行数。
15. 嵌套字典推导式
字典推导式也可以配合嵌套循环和条件筛选。
15.1 生成坐标和值的字典
points = {(x, y): x + y for x in range(3) for y in range(3)}
print(points)
输出:
{(0, 0): 0, (0, 1): 1, (0, 2): 2, (1, 0): 1, (1, 1): 2, (1, 2): 3, (2, 0): 2, (2, 1): 3, (2, 2): 4}
这里:
键是坐标 (x, y)。
值是 x + y。
15.2 只保留符合条件的键值对
points = {(x, y): x * y for x in range(4) for y in range(4) if x * y > 3}
print(points)
输出:
{(2, 2): 4, (2, 3): 6, (3, 2): 6, (3, 3): 9}
15.3 字典推导式展开嵌套数据
假设有学生和课程成绩:
students = {
"张三": {"语文": 90, "数学": 85},
"李四": {"语文": 76, "数学": 92}
}
想变成:
{
("张三", "语文"): 90,
("张三", "数学"): 85,
("李四", "语文"): 76,
("李四", "数学"): 92
}
可以写:
students = {
"张三": {"语文": 90, "数学": 85},
"李四": {"语文": 76, "数学": 92}
}
result = {
(name, subject): score
for name, subjects in students.items()
for subject, score in subjects.items()
}
print(result)
输出:
{('张三', '语文'): 90, ('张三', '数学'): 85, ('李四', '语文'): 76, ('李四', '数学'): 92}
这种写法适合有一定基础后再讲。
16. 嵌套集合推导式
集合推导式也可以嵌套使用。
集合特点:
自动去重,无固定顺序。
16.1 提取二维列表中的不同数字
matrix = [
[1, 2, 2],
[3, 3, 4],
[4, 5, 5]
]
result = {num for row in matrix for num in row}
print(result)
输出:
{1, 2, 3, 4, 5}
16.2 提取多个单词中的不同字符
words = ["hello", "python"]
chars = {ch for word in words for ch in word}
print(chars)
输出可能是:
{'h', 'e', 'l', 'o', 'p', 'y', 't', 'n'}
16.3 筛选并去重
matrix = [
[1, 2, 3],
[2, 4, 6],
[3, 6, 9]
]
evens = {num for row in matrix for num in row if num % 2 == 0}
print(evens)
输出:
{2, 4, 6}
注意:
列表推导式保留重复元素。
集合推导式会自动去重。
17. 多层嵌套推导式
推导式中可以出现三层甚至更多层循环。
例如:
result = [(x, y, z) for x in [1, 2] for y in [3, 4] for z in [5, 6]]
print(result)
输出:
[(1, 3, 5), (1, 3, 6), (1, 4, 5), (1, 4, 6), (2, 3, 5), (2, 3, 6), (2, 4, 5), (2, 4, 6)]
等价于:
result = []
for x in [1, 2]:
for y in [3, 4]:
for z in [5, 6]:
result.append((x, y, z))
print(result)
但是教学和实际开发中要注意:
超过两层嵌套时,推导式很容易变得难读。
如果学生读起来吃力,应该改成普通循环。
18. 推导式中的多个 if
推导式可以有多个 if。
nums = range(1, 21)
result = [x for x in nums if x % 2 == 0 if x % 3 == 0]
print(result)
输出:
[6, 12, 18]
它等价于:
nums = range(1, 21)
result = []
for x in nums:
if x % 2 == 0:
if x % 3 == 0:
result.append(x)
print(result)
也等价于:
result = [x for x in range(1, 21) if x % 2 == 0 and x % 3 == 0]
教学建议:
简单多个条件,用 and 更直观。
有明显层级关系时,可以使用多个 if。
19. 推导式中的函数调用
推导式中的表达式可以调用函数。
19.1 使用函数处理数据
def clean_name(name):
return name.strip()
names = [" 张三 ", " 李四", "王五 "]
result = [clean_name(name) for name in names]
print(result)
输出:
['张三', '李四', '王五']
19.2 使用函数判断条件
def is_valid_score(score):
return 0 <= score <= 100
scores = [90, 120, 85, -5, 60]
result = [score for score in scores if is_valid_score(score)]
print(result)
输出:
[90, 85, 60]
教学建议:
如果推导式里的判断条件太长,可以封装成函数,让代码更清楚。
20. 推导式与可读性
推导式的优点是简洁。
但简洁不等于越短越好。
20.1 适合用推导式的情况
适合:
squares = [x * x for x in range(10)]
适合:
evens = [x for x in nums if x % 2 == 0]
适合:
points = [(x, y) for x in range(3) for y in range(3)]
这些逻辑都比较简单,使用推导式很清楚。
20.2 不适合用推导式的情况
不推荐:
result = [
"优秀" if score >= 90 else "良好" if score >= 80 else "及格" if score >= 60 else "不及格"
for row in all_scores
for score in row
if score is not None
]
虽然可以运行,但读起来比较费劲。
更推荐:
result = []
for row in all_scores:
for score in row:
if score is not None:
if score >= 90:
result.append("优秀")
elif score >= 80:
result.append("良好")
elif score >= 60:
result.append("及格")
else:
result.append("不及格")
教学总结:
一眼能看懂,用推导式。
需要想半天,改成普通循环。
21. 常见错误和注意事项
21.1 把 for 的顺序写反
错误示例:
matrix = [[1, 2], [3, 4]]
result = [num for num in row for row in matrix] # 错误
原因是:
row 还没有被定义,就先使用了 row。
正确写法:
matrix = [[1, 2], [3, 4]]
result = [num for row in matrix for num in row]
print(result)
输出:
[1, 2, 3, 4]
21.2 分不清筛选 if 和 if...else
筛选:
[x for x in nums if x > 0]
转换:
[x if x > 0 else 0 for x in nums]
记忆:
后面的 if 用来筛选。
前面的 if...else 用来二选一生成结果。
21.3 嵌套太深导致难读
不推荐:
result = [(a, b, c, d) for a in A for b in B for c in C for d in D if a + b + c + d > 10]
更推荐写成普通循环,或者拆成多个步骤。
21.4 集合推导式会去重
nums = [1, 1, 2, 2, 3]
result = {x for x in nums}
print(result)
输出:
{1, 2, 3}
如果需要保留重复数据,不要使用集合推导式。
21.5 集合没有固定顺序
result = {x for x in [3, 1, 2]}
print(result)
输出顺序不一定是:
{3, 1, 2}
如果需要固定顺序,请使用列表推导式。
21.6 字典推导式要注意键重复
words = ["apple", "ant", "banana", "book"]
result = {word[0]: word for word in words}
print(result)
输出可能是:
{'a': 'ant', 'b': 'book'}
原因是:
字典的键不能重复。
后面的值会覆盖前面的值。
21.7 不要用推导式只为了执行动作
不推荐:
[print(x) for x in range(5)]
推荐:
for x in range(5):
print(x)
推导式主要用于生成新数据,不适合只用来打印、写文件、修改外部状态。
21.8 大数据量时注意内存
列表推导式会一次性生成完整列表。
result = [x for x in range(10000000)]
如果数据量特别大,会占用较多内存。
这种情况下可以考虑生成器表达式:
result = (x for x in range(10000000))
不过对初学者来说,先掌握列表、字典、集合推导式即可。
21.9 圆括号不是元组推导式
result = (x * x for x in range(5))
print(result)
输出类似:
<generator object <genexpr> at 0x...>
这不是元组,而是生成器表达式。
如果想生成元组,要写:
result = tuple(x * x for x in range(5))
print(result)
输出:
(0, 1, 4, 9, 16)
22. 综合案例
22.1 从二维成绩表中筛选及格成绩
scores = [
[90, 58, 76],
[45, 88, 92],
[60, 59, 100]
]
passed = [score for row in scores for score in row if score >= 60]
print(passed)
输出:
[90, 76, 88, 92, 60, 100]
22.2 把二维成绩表中的不及格分数改为 0
scores = [
[90, 58, 76],
[45, 88, 92],
[60, 59, 100]
]
result = [[score if score >= 60 else 0 for score in row] for row in scores]
print(result)
输出:
[[90, 0, 76], [0, 88, 92], [60, 0, 100]]
注意:
这里保留了二维结构。
外层推导式生成每一行。
内层推导式处理每一行中的每个分数。
22.3 找出两个班共同喜欢的课程组合
假设每个学生可以选择多个课程:
students = {
"张三": ["Python", "Java"],
"李四": ["Python", "C++"],
"王五": ["Java", "C++"]
}
result = [(name, course) for name, courses in students.items() for course in courses]
print(result)
输出:
[('张三', 'Python'), ('张三', 'Java'), ('李四', 'Python'), ('李四', 'C++'), ('王五', 'Java'), ('王五', 'C++')]
22.4 统计所有学生选择过的不同课程
students = {
"张三": ["Python", "Java"],
"李四": ["Python", "C++"],
"王五": ["Java", "C++"]
}
courses = {course for course_list in students.values() for course in course_list}
print(courses)
输出:
{'Python', 'Java', 'C++'}
集合推导式会自动去重。
22.5 生成学生课程编号字典
students = {
"张三": ["Python", "Java"],
"李四": ["Python", "C++"]
}
result = {
f"{name}-{course}": len(course)
for name, courses in students.items()
for course in courses
}
print(result)
输出:
{'张三-Python': 6, '张三-Java': 4, '李四-Python': 6, '李四-C++': 3}
23. 课堂练习
练习 1:生成所有坐标点
请使用嵌套列表推导式生成以下坐标:
[(0, 0), (0, 1), (1, 0), (1, 1)]
参考答案:
points = [(x, y) for x in range(2) for y in range(2)]
print(points)
练习 2:展平二维列表
有如下二维列表:
matrix = [[1, 2], [3, 4], [5, 6]]
请把它变成一维列表:
[1, 2, 3, 4, 5, 6]
参考答案:
matrix = [[1, 2], [3, 4], [5, 6]]
result = [num for row in matrix for num in row]
print(result)
练习 3:筛选二维列表中的偶数
matrix = [[1, 2, 3], [4, 5, 6]]
请筛选出所有偶数。
参考答案:
matrix = [[1, 2, 3], [4, 5, 6]]
evens = [num for row in matrix for num in row if num % 2 == 0]
print(evens)
练习 4:生成乘积大于 10 的组合
a = [1, 2, 3, 4]
b = [3, 4, 5]
请生成所有乘积大于 10 的组合。
参考答案:
a = [1, 2, 3, 4]
b = [3, 4, 5]
result = [(x, y) for x in a for y in b if x * y > 10]
print(result)
练习 5:生成 3 行 3 列的二维列表
请生成:
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
参考答案:
matrix = [[0 for col in range(3)] for row in range(3)]
print(matrix)
练习 6:把不及格成绩改成 0
scores = [[90, 58], [76, 45]]
请把不及格成绩改成 0,并保留二维结构。
参考答案:
scores = [[90, 58], [76, 45]]
result = [[score if score >= 60 else 0 for score in row] for row in scores]
print(result)
练习 7:提取不同字符
words = ["hello", "python"]
请用集合推导式提取所有不同字符。
参考答案:
words = ["hello", "python"]
chars = {ch for word in words for ch in word}
print(chars)
练习 8:生成坐标字典
请生成如下形式的字典:
{
(0, 0): 0,
(0, 1): 1,
(1, 0): 1,
(1, 1): 2
}
参考答案:
result = {(x, y): x + y for x in range(2) for y in range(2)}
print(result)
练习 9:筛选非空姓名
names = [[" 张三 ", ""], [" 李四", " "], ["王五"]]
请把二维列表中的姓名取出,去掉空格,并过滤空字符串。
参考答案:
names = [[" 张三 ", ""], [" 李四", " "], ["王五"]]
result = [name.strip() for row in names for name in row if name.strip()]
print(result)
练习 10:判断代码是否合适
下面代码是否推荐?
[print(x) for x in range(5)]
参考答案:
不推荐。
推导式主要用于生成新数据。
如果只是打印,应该使用普通 for 循环。
推荐写法:
for x in range(5):
print(x)
24. 课堂总结
嵌套推导式和条件筛选可以让我们用较短的代码处理复杂数据。
一句话总结:
嵌套推导式就是把嵌套 for 循环写进推导式中。
条件筛选就是用 if 保留符合条件的数据。
常用写法:
[表达式 for x in 数据 if 条件]
[表达式 for x in 数据1 for y in 数据2]
[表达式 for x in 数据1 for y in 数据2 if 条件]
[值1 if 条件 else 值2 for x in 数据]
[[表达式 for 内层变量 in 内层数据] for 外层变量 in 外层数据]
教学记忆口诀:
先看 for,后看 if,
多个 for,顺序读。
后置 if 是筛选,
前置 if else 是转换。
嵌套太深别硬写,
普通循环更清楚。
最后记住一个原则:
推导式适合简单、清晰的数据生成和筛选。
如果代码看起来绕,就大胆改回普通 for 循环。