Python嵌套列表——列表里的“小房间”
中等2Python嵌套列表:像收纳盒一样整理数据
同学们,你们见过那种带分层抽屉的收纳盒吗?一个大盒子里有多个小抽屉,每个小抽屉里还能放更小的盒子。在Python中,列表就像这种收纳盒——它可以装下各种东西,甚至能装下其他列表!这种“列表里套列表”的结构,就叫做嵌套列表。它能帮我们把有结构的数据(比如表格、棋盘、成绩册)整整齐齐地存起来。
一、创建与访问:像打开柜子拿东西
1. 先看一个生活例子
老师要记录三个小组的数学成绩:第一组有小红(95)、小明(88)、小刚(92);第二组有小丽(78)、小华(85);第三组有小强(90)、小美(96)、小芳(87)。如果只用一列列表,成绩混在一起就分不清谁是哪组的。用嵌套列表,就像给每个小组单独画一个小格子:
# 三个小组的成绩,每个小组是一个小列表
scores = [
[95, 88, 92], # 第一组:小红、小明、小刚
[78, 85], # 第二组:小丽、小华
[90, 96, 87] # 第三组:小强、小美、小芳
]
外层列表 scores 里有3个元素,每个元素又是一个列表。访问的方法就像先确定大抽屉,再确定小格子:scores[0] 拿到第一组列表 [95, 88, 92],然后 scores[0][1] 拿到这个列表的第1项(小明)——结果是 88。记住:索引从0开始哦!
2. 用嵌套列表表示二维表格(比如教室座位)
# 创建一个3行4列的空座位表(每个座位暂时用字符串"空")
seats = [
["空", "空", "空", "空"],
["空", "空", "空", "空"],
["空", "空", "空", "空"]
]
# 让第二行第三列的同学坐下(行索引1,列索引2)
seats[1][2] = "小强"
print(seats) # 输出:[['空','空','空','空'], ['空','空','小强','空'], ['空','空','空','空']]
3. 创建二维列表的快捷方式(列表推导式)
有时候我们需要生成一个固定大小的“棋盘”或“网格”。比如一个5行5列、所有格子初始为0的矩阵:
# 用列表推导式创建5行5列的矩阵,每个格子初始为0
matrix = [[0 for _ in range(5)] for _ in range(5)]
# 等价于下面的循环写法(但更简洁):
# matrix = []
# for i in range(5):
# row = []
# for j in range(5):
# row.append(0)
# matrix.append(row)
print(matrix) # 5行5列全是0
新手容易犯的错(一):索引越界
# 错误示例
scores = [[95, 88, 92], [78, 85]]
print(scores[0][3]) # 第一组只有3个分数,索引0~2,访问索引3会报错 IndexError
记住访问前先确认内层列表的长度,或者用 len() 检查。
二、遍历嵌套列表:像扫地机器人一样扫遍每个角落
想象一下,你是一个仓库管理员,要清点一个大货架。货架有5层,每层有4个格子。你得先从上到下走过每一层,再从左到右查看每个格子的货物。在Python里,遍历嵌套列表正是用这种两层循环的思路:外层循环控制行(外层列表的元素),内层循环控制列(内层列表的元素)。
1. 直接遍历元素(不需要知道索引)
假如我们有一个3行4列的“成绩矩阵”,想打印出每个学生的分数:
# 一个3个班、每个班4个学生的成绩表(行是班级,列是学生编号)
grades = [
[85, 92, 78, 90],
[88, 76, 95, 83],
[91, 89, 77, 94]
]
# 外层循环:遍历每一班(每一行)
for row in grades:
# 内层循环:遍历这个班里的每个学生成绩
for score in row:
print(score, end=" ") # 打印分数,不换行
print() # 打印完一行的所有分数后换行
输出:
85 92 78 90
88 76 95 83
91 89 77 94
2. 用索引遍历(可以知道是第几行第几列)
for i in range(len(grades)): # i 代表行索引(从0开始)
for j in range(len(grades[i])): # j 代表列索引
print(f"第{i+1}班第{j+1}个学生: {grades[i][j]}")
注意 len(grades) 得到外层列表的长度(行数),len(grades[i]) 得到第i行列表的长度(列数)。
3. 各行的长度不一样怎么办?
比如前面那个成绩例子中,第一组3人、第二组2人、第三组3人。遍历时直接使用 for score in group 即可,自动适应每一行的长度:
scores = [[95, 88, 92], [78, 85], [90, 96, 87]]
for group in scores:
for score in group:
print(score, end=" ")
print()
4. 用 enumerate 同时获取索引和值
for row_idx, row in enumerate(grades):
for col_idx, val in enumerate(row):
print(f"grades[{row_idx}][{col_idx}] = {val}")
新手容易犯的错(二):忘记内层循环
# 错误示例:只写了一层循环,打印的是内层列表本身
for row in grades:
print(row) # 输出:[85,92,78,90] 等,不是单个分数
要访问每个元素,一定要嵌套两层的 for 循环。
三、嵌套列表的常见操作:修改、添加、删除
1. 修改某个元素
# 把第二组第一个成绩78改成80
scores[1][0] = 80
print(scores) # 第二组变成 [80, 85]
2. 给某一整行添加新元素
# 给第一组增加一个新同学的成绩99
scores[0].append(99)
print(scores) # 第一组变成 [95, 88, 92, 99]
3. 添加一个新行(新小组)
# 增加第四组,成绩为 [100, 99]
scores.append([100, 99])
print(scores) # 现在有4个小组
4. 删除一行或一列
# 删除第三组(索引2)
del scores[2]
# 删除第二组的第一个成绩(索引0)
del scores[1][0]
四、嵌套列表在实际生活中的应用
应用1:五子棋棋盘状态
五子棋的棋盘是15行15列的格子,每个格子可以是空、黑子或白子。用嵌套列表表示当前局面:
# 创建一个15x15的空棋盘(所有格子的值为0表示空)
board = [[0 for _ in range(15)] for _ in range(15)]
# 玩家在第7行第7列落下一颗黑子(假设黑子用1表示)
board[6][6] = 1 # 注意索引从0开始
# 打印棋盘前5行前5列示意
for row in board[:5]:
print(row[:5])
应用2:学生成绩统计
小明老师有三个班,每个班人数不同。用嵌套列表存成绩,然后计算每个班的平均分:
scores = [
[90, 85, 92, 78, 88], # 一班5人
[79, 94, 81, 86], # 二班4人
[88, 92, 95, 87, 93, 89] # 三班6人
]
for i, class_scores in enumerate(scores):
total = sum(class_scores) # 这个班的总分
avg = total / len(class_scores) # 平均分
print(f"第{i+1}班平均分: {avg:.2f}")
应用3:商场货架库存
一个商场有3排货架,每排有4个不同的商品,用嵌套列表记录每个位置的库存数量,然后寻找库存最少的货架:
stock = [
[10, 25, 8, 12],
[30, 5, 18, 22],
[14, 20, 6, 9]
]
min_stock = float('inf') # 初始化最小值很大
min_shelf = -1
for i, shelf in enumerate(stock):
shelf_min = min(shelf) # 这一排的最小库存
if shelf_min < min_stock:
min_stock = shelf_min
min_shelf = i
print(f"库存最少的货架是第{min_shelf+1}排,最小库存为{min_stock}")
应用4:简易井字棋(完整示例)
写一个程序,用嵌套列表表示井字棋棋盘(3×3),模拟下棋并判断胜负:
# 井字棋棋盘,初始全部为空格' '
board = [
[' ', ' ', ' '],
[' ', ' ', ' '],
[' ', ' ', ' ']
]
# 模拟下棋:玩家1(X)在第1行第1列落子,玩家2(O)在第2行第2列落子
board[0][0] = 'X'
board[1][1] = 'O'
board[0][1] = 'X'
board[2][2] = 'O'
board[0][2] = 'X' # 此时第一行全是X,玩家1获胜
# 打印当前棋盘
print("当前棋盘:")
for row in board:
print('|'.join(row))
print('-----')
# 判断第一行是否全是X
if board[0][0] == board[0][1] == board[0][2] == 'X':
print("玩家1(X)获胜!")
五、新手容易犯的错误总结
| 错误类型 | 错误示例 | 正确做法 |
|---|---|---|
| 索引越界 | scores[0][3],但该行只有3个元素 | 先 len(scores[0]) 检查长度 |
| 忘记内层循环 | for row in grades: print(row) | 必须两层循环才能访问每个元素 |
| 创建时误用复制 | board = [[0]*5]*3(浅复制,所有行指向同一个列表) | 用列表推导式 [[0]*5 for _ in range(3)] |
| 修改整行时只改一个元素 | 想要将第一行全改为0,却写 board[0] = [0,0,0,0](这是替换整行,有时可用) | 根据需求选择替换或逐个修改 |
特别提醒:创建嵌套列表时,千万避免用 [[0]*3]*4 这种写法,因为内层列表会被重复引用,修改一个元素会影响所有行。用列表推导式才是安全的。
六、相关指引
学会嵌套列表后,你还可以继续学习:
- 列表推导式的高级用法:快速生成复杂二维结构
- 矩阵运算:用嵌套列表实现加法、乘法
- 图像处理:把图片当作像素矩阵(嵌套列表)
- 海龟绘图:用嵌套列表存储路径坐标
- JSON数据处理:嵌套列表与字典结合,处理更复杂的数据
嵌套列表就像一张“二维表格”,让Python能处理生活中遇到的各种结构化数据。下次当你需要按行、列整理数据时(比如日历、课表、地图、游戏地图),别忘了这个好帮手哦!
例题精讲
已知 `matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]`,要获取数字 6,正确的表达式是?
已知 `my_list = [[0]*3 for _ in range(3)]`,执行 `my_list[1][1] = 5` 后,整个列表变为 `[[0,0,0],[0,5,0],[0,0,0]]`。
请补全代码,创建一个 2x2 的嵌套列表(矩阵),第一行元素为 1 和 2,第二行元素为 3 和 4,并赋值给变量 `mat`。
`mat = ___`下列关于嵌套列表遍历的说法,哪一个是正确的?
已知 `score = [[90, 85], [88, 92], [78, 80]]`,要把第二个同学的第二门课成绩改为 95,请补全代码。
`score[___][___] = 95`