CC++ & Algorithm

Python嵌套列表——列表里的“小房间”

中等2
语言版本:C++Python
概述:嵌套列表就像一个大柜子,每个格子里还能再放小柜子,帮助我们把有结构的数据整齐地存起来。

Python嵌套列表:像收纳盒一样整理数据

同学们,你们见过那种带分层抽屉的收纳盒吗?一个大盒子里有多个小抽屉,每个小抽屉里还能放更小的盒子。在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能处理生活中遇到的各种结构化数据。下次当你需要按行、列整理数据时(比如日历、课表、地图、游戏地图),别忘了这个好帮手哦!

例题精讲

1单选题

已知 `matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]`,要获取数字 6,正确的表达式是?

Amatrix[2][1]
Bmatrix[1][2]
Cmatrix[2][2]
Dmatrix[1][1]
2判断题

已知 `my_list = [[0]*3 for _ in range(3)]`,执行 `my_list[1][1] = 5` 后,整个列表变为 `[[0,0,0],[0,5,0],[0,0,0]]`。

3填空题
请补全代码,创建一个 2x2 的嵌套列表(矩阵),第一行元素为 1 和 2,第二行元素为 3 和 4,并赋值给变量 `mat`。
`mat = ___`
4单选题

下列关于嵌套列表遍历的说法,哪一个是正确的?

A`for row in matrix:` 遍历的是每个子列表中的所有元素
B要遍历所有元素,必须使用两层循环,外层遍历子列表,内层遍历元素
C使用 `for i in range(len(matrix)):` 只能获得行索引,无法获得元素
D可以直接用 `for item in matrix:` 打印出所有元素的值
5填空题
已知 `score = [[90, 85], [88, 92], [78, 80]]`,要把第二个同学的第二门课成绩改为 95,请补全代码。
`score[___][___] = 95`