外观
第8周:第五次上机课
一、二维列表:列表里还可以放列表
对应 04 · 矩阵换行求边缘和。
1. 先找行,再找这一行中的元素
python
matrix = [[2, 4, 6], [1, 3, 5]]
print(matrix[0]) # [2, 4, 6],第 1 行
print(matrix[0][1]) # 4,第 1 行第 2 个元素
print(len(matrix)) # 2,行数
print(len(matrix[0])) # 3,列数matrix[i][j] 可以分成两步理解:matrix[i] 取出一整行,再用 [j] 取出这一行中的元素。下标从 0 开始。
2. 修改一个元素和交换两行
python
matrix[0][1] = 9
matrix[0], matrix[1] = matrix[1], matrix[0]
print(matrix) # [[1, 3, 5], [2, 9, 6]]一行本身也是一个列表,可以像普通变量一样交换。a, b = b, a 会先取得右侧的两个值,再分别赋给左侧。
3. 用两层循环访问位置
python
for i in range(len(matrix)):
for j in range(len(matrix[i])):
print(i, j, matrix[i][j])外层决定走到哪一行,内层走过这一行的各列。
做题前想一想: 第 1 行对应哪个下标?最后一行呢?一个位置在边缘,可以通过它的行、列下标判断吗?
二、列表的赋值与复制
对应 05 · 图像模糊处理。
1. 两个变量可能指向同一个列表
python
a = [10, 20, 30]
b = a
b[0] = 99
print(a) # [99, 20, 30]b = a 没有新建列表。通过 b 修改元素,a 看到的内容也会变。
python
a = [10, 20, 30]
b = a[:]
b[0] = 99
print(a) # [10, 20, 30]对于这个整数列表,切片 a[:] 生成一个独立的新列表。
2. 二维列表要考虑里面的每一行
python
image = [[10, 20], [30, 40]]
result = []
for row in image:
result.append(row[:])
result[0][0] = 99
print(image[0][0]) # 10这里逐行复制。仅写 image[:] 只新建外面的列表,里面的行仍然共用。
3. 用下标描述相邻位置
假设当前位置是 (i, j),上一行是 i-1,下一行是 i+1,左一列是 j-1,右一列是 j+1。先在纸上画一个小方格,标出这些位置。
做题前想一想: 最外侧的点都有这四个邻居吗?题面要求使用“原灰度值”,计算新值时应该从哪个列表读取?
三、排序:先整理数据,再观察关系
对应 07 · 小鹿的工作和休息时间。
1. 用两个数表示一个时间段
python
period = (2, 6)
start, end = period
print(end - start) # 4元组可以把相关的数据放在一起;解包把它们分别交给两个变量。时间段长度是终点减起点。
2. 让一组时间段按开始时间排列
python
periods = [(8, 10), (2, 6), (5, 7)]
ordered = sorted(periods, key=lambda item: item[0])
print(ordered) # [(2, 6), (5, 7), (8, 10)]sorted 返回排序后的新列表;key 告诉它“按什么比较”。这里每个 item 是一个时间段,item[0] 是开始时间。
lambda item: item[0] 相当于下面这个只做一件事的小函数:
python
def get_start(item):
return item[0]
ordered = sorted(periods, key=get_start)3. 在时间轴上看两个区间
先画 [2,6],再分别画 [5,8]、[6,8]、[7,9],观察重叠、相接和有空隙的区别。判断关系时,需要比较哪些端点?
做题前想一想: 输入的时间段是乱序的,先排序有什么帮助?两段工作能连续进行,需要满足什么条件?
四、字典:用名字找到对应的数据
对应 09 · 单词出现频率统计。
1. 列表用下标,字典用键
python
counts = {"apple": 2, "pear": 1}
print(counts["apple"]) # 2
print(counts.get("banana", 0)) # 0字典保存“键 → 值”的对应关系。get(key, 0) 表示:存在这个键就取出它的值,否则返回 0;这一步本身不会添加新键。
2. 从空字典开始计数
python
counts = {}
for fruit in ["apple", "pear", "apple"]:
counts[fruit] = counts.get(fruit, 0) + 1
print(counts) # {'apple': 2, 'pear': 1}每次先取旧值,再加 1,最后存回字典。第一次看到 apple,从 0 加到 1;再次看到它,从 1 加到 2。
3. 同时取出键和值
python
for name, count in counts.items():
print(name, count)items() 可以遍历每一对键和值。若要排序,可以把这些二元组交给 sorted;排序依据由 key 指定。
做题前想一想: 统计单词时,什么作为键、什么作为值?如果两个词次数相同,题目希望按什么顺序输出?
五、字典累加与函数:把一条记录变成一个数
对应 10 · 网站网页访问统计。
1. 字典里的值不一定每次加 1
python
totals = {}
for name, amount in [("apple", 3), ("pear", 2), ("apple", 4)]:
totals[name] = totals.get(name, 0) + amount
print(totals) # {'apple': 7, 'pear': 2}计数是每次加 1,求总量是每次加当前记录的数值。两者都要保留之前的累计结果。
2. 拆开字符串,再统一单位
python
text = "01:02:03"
hour, minute, second = text.split(":")
print(hour, minute, second) # 01 02 03拆出来的仍是字符串,要先转成整数才能计算。比较或相减之前,把时、分、秒统一为秒:一小时 3600 秒,一分钟 60 秒。
如果多处都需要相同的转换,可以把它写成函数,用参数接收时间字符串,用 return 返回秒数。
做题前想一想: 一条访问记录能算出什么?同一网页出现多次时,字典里应该保存最后一次的时长,还是累计时长?
六、字典中的值也可以是列表
对应 11 · 单词打分(提高版)。
1. 把同一类记录放在一起
python
scores = {}
for subject, score in [("math", 80), ("english", 90), ("math", 100)]:
if subject not in scores:
scores[subject] = []
scores[subject].append(score)
print(scores) # {'math': [80, 100], 'english': [90]}第一次遇到某个科目,先给它建一个空列表;之后把这个科目的分数追加进去。scores[subject] 取出来的是列表,所以可以继续调用 append()。
2. 一组数的总和、个数和平均值
python
values = scores["math"]
print(sum(values)) # 180
print(len(values)) # 2
print(sum(values) / len(values)) # 90.0平均值由总和与个数共同决定。也可以不保存全部分数,只记录总分和次数;选择怎样存数据,要看后面还需要用哪些信息。
做题前想一想: 如果最后既要输出单词,又要输出给它评分的人,只保存分数够吗?哪些信息需要在读取时一起留下?