Python二维列表完全指南:创建、遍历、矩阵运算及深拷贝陷阱
在Python开发中,一维列表能解决的问题有限,而二维列表(嵌套列表)才是处理表格、棋盘、图像等结构化数据的核心工具。本文将从创建、访问、修改、矩阵运算到深拷贝陷阱,系统梳理二维列表的实战技巧,并提供可直接运行的代码示例。一、创建二维列表的正确姿势
1. 字面量创建(适用于小型固定数据)
matrix = [
,
,
]
print(matrix) #
print(matrix) # 6
print(len(matrix)) # 3
print(len(matrix)) # 3
2. 推导式创建(推荐)
推导式能生成规则矩阵,且每个内层列表都是独立对象。
# 3行4列全零矩阵
zeros = [ for _ in range(3)]
print(zeros)
# 乘法表
table = [ for i in range(1, 6)]
for row in table:
print(row)
3. 经典陷阱:乘法创建
wrong = [ * 4] * 3
wrong = 999
print(wrong)# [, , ]
# 三行都变了!因为 *3 复制的是同一内层列表的引用
print(wrong is wrong)# True
# 正确做法
correct = [ * 4 for _ in range(3)]
correct = 999
print(correct)# [, , ]
# 只有第一行变化
乘法创建造成的“引用共享”是Python新手最易踩的坑,务必备注使用推导式。
4. 不规则(锯齿)二维列表
jagged = [
,
,
]
for i, row in enumerate(jagged):
print(f'第{i}行有{len(row)}列')
二、访问与遍历
1. 索引操作
matrix = [
,
,
]
print(matrix) # 1
print(matrix) # 7
print(matrix[-1][-1]) # 12
print(matrix) # 整行
col_0 = for row in matrix]# 整列
print(col_0) #
2. 遍历推荐(enumerate双重循环)
for i, row in enumerate(matrix):
for j, value in enumerate(row):
print(f'matrix[{i}][{j}] = {value}')
3. 行列切片与子矩阵
print(matrix[:2])#
def submatrix(mat, rs, re, cs, ce):
return for row in mat]
三、修改二维列表
1. 修改单个元素或整行
matrix = 99
matrix =
# 修改整列需循环
for row in matrix:
row = 0
2. 增删行列
matrix.append() # 加一行
for i, row in enumerate(matrix):# 加一列
row.append((i + 1) * 10)
del matrix # 删一行
for row in matrix: # 删一列
del row[-1]
matrix.insert(1, ) # 插入一行
四、矩阵运算实战
1. 转置
def transpose(mat):
if not mat:
return []
rows, cols = len(mat), len(mat)
return [ for i in range(rows)] for j in range(cols)]
# 或用 zip 简洁实现
transposed =
2. 加法与数乘
def matrix_add(a, b):
rows, cols = len(a), len(a)
return [ + b for j in range(cols)] for i in range(rows)]
def matrix_scalar_mul(mat, scalar):
return [ for row in mat]
3. 矩阵乘法
def matrix_multiply(a, b):
if not a or not b:
return []
if len(a) != len(b):
raise ValueError('矩阵尺寸不匹配')
rows_a, cols_a = len(a), len(a)
cols_b = len(b)
result = [ * cols_b for _ in range(rows_a)]
for i in range(rows_a):
for j in range(cols_b):
result = sum(a * b for k in range(cols_a))
return result
# 验证:2×3 乘 3×2 得 2×2
a = [, ]
b = [, , ]
c = matrix_multiply(a, b)
print(c)# [, ]
五、棋盘游戏经典应用
1. 井字棋(Tic-Tac-Toe)
二维列表天然适合表示3×3棋盘,以下简化版状态机可实现胜负判断与落子。
class TicTacToe:
def __init__(self):
self.board = [[' ' for _ in range(3)] for _ in range(3)]
self.current_player = 'X'
def display(self):
print('0 1 2')
for i, row in enumerate(self.board):
print(f'{i} ' + ' | '.join(row))
if i < 2:
print(' ---+---+---')
def make_move(self, row, col):
if self.board != ' ':
return False
self.board = self.current_player
self.current_player = 'O' if self.current_player == 'X' else 'X'
return True
def check_winner(self):
b = self.board
# 检查行、列、对角线
for row in b:
if row == row == row != ' ':
return row
for col in range(3):
if b == b == b != ' ':
return b
if b == b == b != ' ':
return b
if b == b == b != ' ':
return b
if all(cell != ' ' for row in b for cell in row):
return '平局'
return None
2. 扫雷棋盘生成
随机布雷后,用方向数组计算周围雷数。
import random
def create_minesweeper(rows, cols, mines):
board = [ for _ in range(rows)]
mine_positions = set()
while len(mine_positions) < mines:
r = random.randint(0, rows - 1)
c = random.randint(0, cols - 1)
mine_positions.add((r, c))
board = -1
directions = [(-1,-1), (-1,0), (-1,1), (0,-1),
(0,1), (1,-1), (1,0), (1,1)]
for r, c in mine_positions:
for dr, dc in directions:
nr, nc = r + dr, c + dc
if 0 <= nr < rows and 0 <= nc < cols and board != -1:
board += 1
return board
board = create_minesweeper(8, 8, 10)
for row in board:
print(' '.join(f'{cell:2d}' for cell in row))
六、数据表格处理
1. CSV解析与排序
def parse_csv(text, delimiter=','):
lines = text.strip().split('\n')
return
csv_text = '''姓名,年龄,城市,职业
小明,25,北京,工程师
小红,23,上海,设计师
小刚,26,广州,分析师'''
data = parse_csv(csv_text)
def sort_by_column(data, col_index, numeric=False):
headers = data
body = data
key_fn = lambda row: float(row) if numeric else row
body.sort(key=key_fn)
return + body
sorted_data = sort_by_column(data, 1, numeric=True)
for row in sorted_data:
print(row)
2. 数据透视表模拟
def pivot_table(data, row_field, col_field, value_field, agg_func=sum):
row_values = sorted(set(d for d in data))
col_values = sorted(set(d for d in data))
pivot = [ for _ in range(len(row_values))]
row_idx = {v: i for i, v in enumerate(row_values)}
col_idx = {v: i for i, v in enumerate(col_values)}
groups = {}
for record in data:
key = (record, record)
groups.setdefault(key, []).append(record)
for (r, c), values in groups.items():
pivot]] = agg_func(values)
return pivot, row_values, col_values
七、三维列表与更深的嵌套
三维列表由多个二维平面堆叠而成,创建时仍需防范引用共享。
depth, rows, cols = 2, 3, 4
cube = [[ for _ in range(rows)] for _ in range(depth)]
cube = 99
print(cube)# 99
for p, plane in enumerate(cube):
print(f'平面 {p}:')
for row in plane:
print(row)
八、深拷贝与浅拷贝陷阱
嵌套列表的复制必须注意:浅拷贝只复制外层,内层列表共享引用。
import copy
original = [, ]
shallow = original[:] # 浅拷贝
shallow = 999
print(original)# [, ] 已被修改
deep = copy.deepcopy(original)
deep = 888
print(original)# [, ] 不受影响
如果不希望引入copy模块,可手动深拷贝二维列表:
for row in original]
。
总结:创建二维列表永远使用推导式;遍历推荐enumerate双重循环;矩阵运算掌握转置、加法、乘法;数据表格可用列表模拟CSV和透视;深拷贝是避免意外修改的关键。掌握这些技巧,二维列表将成为你处理结构化数据的得力工具。
Re: Python二维列表完全指南:创建、遍历、矩阵运算及深拷贝陷阱
很棒的文章!从创建到矩阵运算都讲得很清晰,特别是那个乘法创建陷阱的示例,直接对比 `wrong` 和 `correct` 的效果,新手一看就能明白为什么不能用 `[*4]*3`。 不过标题里提到了“深拷贝陷阱”,正文中主要讲了乘法造成的引用共享,如果能把 `copy.deepcopy` 和 `copy.copy` 对二维列表的影响也加进来,比如直接用 `.copy()` 复制外层列表后内层还是同一引用,那就更完整了。当然,现在的讲解已经很实用了,特别是 `submatrix` 函数和用 `zip` 实现转置的技巧,直接拿来就能用。感谢分享!Re: Python二维列表完全指南:创建、遍历、矩阵运算及深拷贝陷阱
感谢分享这么详细的二维列表教程!从创建到矩阵运算都覆盖了,特别提醒了乘法创建陷阱和推荐推导式,对新手很友好。 不过我看代码里有两个小细节想确认一下: - 转置函数里 `[ for j in range(cols)]` 这里 `mat` 是不是笔误了?应该是 `mat` 才对吧。 - 矩阵乘法的内循环求和那行 `result = sum(a * b for k in range(cols_a))` 也漏了索引,应该是 `a * b`。 另外标题提到深拷贝陷阱,正文好像没有展开讲?如果能补充一段关于 `copy.deepcopy` 与浅拷贝在二维列表上的区别就更完整了。Re: Python二维列表完全指南:创建、遍历、矩阵运算及深拷贝陷阱
感谢楼主的详细整理!正好最近在处理二维列表的深拷贝问题,看到这篇指南非常及时。内容从基础到进阶都覆盖了,特别是乘法创建陷阱和转置的两种写法,很实用。 另外,我在看代码示例时发现几个小笔误,不知道是不是排版问题: 1. `transpose` 函数中的列表推导式似乎写成了 `[ for j in range(cols)]`,应该是 `[ for j in range(cols)]` 吧?否则会直接复制整个 `mat` 对象。 2. `matrix_add` 中的 `a + b` 应该是 `a + b`,否则会报错。 3. `matrix_multiply` 里 `result = sum(...)` 这条语句看起来没赋值给具体位置,应该是 `result = sum(a * b for k in range(cols_a))`。 这些小问题不影响整体内容的优秀,楼主看是否需要修正一下,方便后来者直接复制运行。再次感谢分享!
页:
[1]