一、保序还是排序
两种去重方式,结果集相同但顺序不同:
- 保序去重:保留第一次出现的顺序,删除后续重复。适合「名单、ID 列表」这类顺序有意义的场景。
- 排序去重:先排序再去重,结果按字典序排列。适合「需要看分布、要对比差异」的场景。
保序更常用,因为顺序往往承载信息(按时间、按优先级)。
二、去重前要不要清洗
直接按行比对,Alice@x.com 和 alice@x.com (末尾有空格)会被当成两条。常见清洗动作:
- 去掉首尾空白(
trim)。 - 统一大小写(邮箱、域名、标签通常不区分大小写)。
- 去掉全角空格、
\r(Windows 换行残留)、零宽字符。 - 统一分隔符(
;与,)。
清洗规则取决于数据语义:用户名、密码、文件名不能随便统一大小写,邮箱的本地部分严格说也区分大小写(实际几乎没人这么用)。
三、按行去重 vs 按字段去重
- 按行:整行完全相同才算重复。适合纯列表。
- 按字段:CSV 里「按邮箱列去重,保留整行」。这时需要指定「以哪一列为键」,重复时保留第一条还是最后一条。
CSV 场景直接按行去重往往无效,因为同一邮箱的其他列(姓名、时间)可能不同。要按主键列去重,用脚本更靠谱:
import csv
seen, rows = set(), []
with open('in.csv', encoding='utf-8-sig', newline='') as f:
for r in csv.DictReader(f):
k = r['email'].strip().lower()
if k in seen:
continue
seen.add(k)
rows.append(r)
四、Excel 去重的局限
「数据 → 删除重复值」很方便,但有三个问题:
- 长数字(身份证、订单号)在打开时就被转成科学计数,精度已丢失,去重结果不可信。
- 前后空格不会被自动清理,
张三与张三视为不同。 - 大小写默认不敏感(Excel 的去重忽略大小写),有时不是你要的。
所以涉及账号、证件、订单的数据,不要用 Excel 中转。
五、大批量怎么处理
几十万行在浏览器里处理会卡。命令行更合适:
# 保序去重(awk 记录首次出现)
awk '!seen[$0]++' in.txt > out.txt
# 排序去重
sort -u in.txt > out.txt
# 忽略大小写 + 去空白
tr -d '\r' < in.txt | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | awk '!seen[tolower($0)]++' > out.txt
awk '!seen[$0]++' 是保序去重的经典写法:第一次见到时 seen[$0] 为 0(取反为真,打印),之后自增为非 0(不打印)。
六、去重后要核对
去重最容易出的问题是「删多了」:
- 统计前后行数:
wc -l。 - 抽样对比:去重前的重复项是否真的重复。
- 确认清洗规则没有误伤(比如把
A和a当成同一个,但业务上它们是不同账号)。
用 文本对比 把「去重前」和「去重后」比一下,能直观看到删了哪些行。
七、另外两种「去重」
- 相似去重(模糊去重):标题略有差异但内容相同,需要相似度算法(编辑距离、SimHash)。文本工具做不到,要用专门方案。
- 按内容哈希去重:计算每行的 MD5/SHA,按哈希去重,效果与按行相同但能处理超长行。
八、工具
小批量(几万行以内)直接粘进 文本去重工具,可选「保序 / 排序」「忽略大小写」「去首尾空白」;去重前后用 字数统计 核对行数与字符数变化。
小结
保序去重保留首次出现顺序,排序去重便于对比;先去空白再统一大小写;CSV 要按字段去重而不是整行;Excel 会毁掉长数字;大批量用 awk '!seen[$0]++' 或 sort -u。