list(set(...))去重最简但不保序,适合纯去重场景;list(dict.fromkeys(...))是保序去重的默认推荐方案;不可哈希对象需手动用seen集合处理。

用 list(set(...)) 去重最简但不保序,适合纯去重场景
直接转 set 再转回 list 是最短写法,底层用哈希表实现,时间复杂度 O(n),但会打乱原始顺序。Python 3.7+ 的 dict 保持插入序,但 set 本身无序——这点常被忽略。
- 适用于:只关心元素唯一性,不依赖原顺序(如统计唯一标签、校验输入合法性)
- 注意:
list(set([1, 2, 2, 3]))可能返回[1, 3, 2],顺序不可预测 - 无法处理不可哈希对象(如字典、列表),会报
TypeError: unhashable type: 'list'
list(dict.fromkeys(...)) 是保序去重的默认推荐方案
利用 Python 3.7+ 字典保持插入顺序的特性,dict.fromkeys() 构造一个键唯一、值为 None 的字典,再取其键转为列表。它既去重又保序,且性能接近 set,是目前最平衡的选择。
- 示例:
list(dict.fromkeys([3, 1, 2, 2, 1, 4]))→[3, 1, 2, 4] - 支持所有可哈希类型(同
set),同样不能用于嵌套列表/字典 - 比手写循环快得多,C 层实现,内存开销略高于
set(多存了None值,但实际影响极小)
遇到不可哈希对象(如字典列表)只能手动遍历 + in 或 seen 集合
当列表含字典、列表等不可哈希类型时,set 和 dict.fromkeys 都会失败。此时必须逐个判断是否已存在,但“怎么判”直接影响效率。
- 错误做法:
[x for i, x in enumerate(lst) if x not in lst[:i]]—— 每次in都是 O(n),整体 O(n²),大数据量卡死 - 正确做法:用
seen = set()记录已见过的 *可哈希标识*,例如对字典用tuple(sorted(d.items()))转成元组;对嵌套列表可用json.dumps(x, sort_keys=True)(需确保内容可序列化) - 若结构简单且元素不多,用
json.dumps(x)作 key 最省事;但要注意浮点精度、NaN 处理等边界
别盲目迷信“最快”,先看数据规模和去重依据
微秒级差异在千条以内数据上毫无意义。真正影响体验的是:你是否需要保序?元素是否可哈希?去重逻辑是“完全相等”还是“某字段唯一”?
立即学习“Python免费学习笔记(深入)”;
- 万级以下:
dict.fromkeys和手写seen集合差别不到 1ms,选可读性强的 - 字段去重(如按字典的
"id"去重):必须用循环 +seen.add(item["id"]),set和dict.fromkeys都不适用 - 重复率极高(如日志中 95% 重复):提前
break或用生成器避免全量构建新列表,比算法本身更重要
list(dict.fromkeys(...)) 就够了;剩下 20% 的麻烦情况,往往卡在“怎么定义‘重复’”,而不是“哪个函数更快”。



















