用映射消除重复劳动
统计课程选择 math, code, math, ai, code, math。为每个课程重新扫描列表会重复劳动,字典把课程名映射到次数,一次扫描就能统计。
choices = ["math", "code", "math", "ai", "code", "math"]
counts = {}
for choice in choices:
counts[choice] = counts.get(choice, 0) + 1
assert counts == {"math": 3, "code": 2, "ai": 1}
assert sum(counts.values()) == len(choices)
get(key, 0) 在键不存在时返回 0。循环不变式是:处理前 项后,每个计数恰等于该值在前 项的出现次数。初始成立;每次只增加当前项的计数,归纳后最终统计正确。
排序要明确平局规则
from collections import Counter
counts = Counter(["math", "code", "math", "ai", "code", "math"])
ranked = sorted(counts.items(), key=lambda item: (-item[1], item[0]))
assert ranked == [("math", 3), ("code", 2), ("ai", 1)]
先取次数的负数使次数从大到小,再按名称打破平局。这样输出规则清晰且可复现。
文本统计需要预处理约定
from collections import Counter
import re
text = "Math, code! Math and AI."
words = re.findall(r"[a-z]+", text.lower())
counts = Counter(words)
assert counts["math"] == 2
assert counts["ai"] == 1
该示例仅适合简单英文字母。中文不能普遍依靠空格分词;连字符、缩写与 Unicode 需要不同规则。预处理决定了统计对象,不是可以忽略的细节。
复杂度与练习
假设字典操作平均为常数时间,统计 项期望用时 ,存储 个不同键需 空间,排序另需 。
练习:将计数转换为相对频率。先检查总数不为零,再用 count / total。频率和应近似 1,浮点比较要使用容差。频率表也是理解经验概率与朴素贝叶斯的起点。
这一节,你理解到哪里了?
这是你的自我反馈,与练习估计、课程进度分别记录。
本文为TheZ原创教学内容。正文采用 CC BY-NC-SA 4.0,代码采用 MIT 许可。请尊重署名与授权范围。