因为set基于哈希表实现,平均查找时间复杂度为O(1),而list的in操作需线性遍历,时间复杂度为O(n);数据量超百条时差异明显,上万条时set可快100倍以上。

为什么用 set 查找比 list 快得多?
因为 list 的 in 操作是 O(n) 线性扫描,而 set 基于哈希表实现,平均查找是 O(1)。当数据量超过几百条,差异就肉眼可见;上万条时,set 可能比 list 快 100 倍以上。
但要注意:这仅对「判重」「是否存在」类操作成立;如果需要保持插入顺序、支持索引访问或允许重复元素,set 就不适用。
如何安全地把已有 list 转成 set 判重?
直接 set(my_list) 最常用,但有三个关键限制必须提前确认:
-
list中所有元素必须是可哈希的(即不可变)——比如不能包含dict、list或自定义未实现__hash__的对象 - 原始顺序会丢失(
set无序),若后续还需按原顺序遍历,得额外存一份list或改用dict.fromkeys(my_list).keys()(Python 3.7+ 保序) - 重复元素会被自动去重,如果你本意是“统计出现次数”,该用
collections.Counter而非set
set 判重的典型写法和易错点
常见错误不是语法问题,而是逻辑误用:
立即学习“Python免费学习笔记(深入)”;
- 写成
if item in my_set: do_something()是对的;但若写成if item in list(set(my_list)):,等于又转回list,白忙一场 - 动态添加过程中反复重建
set(如循环内写seen = set(items))——应该初始化一次,然后用.add()增量更新 - 误以为
set支持下标访问:my_set[0]会直接报TypeError: 'set' object is not subscriptable - 字符串判重时忽略大小写或空格:要统一预处理,比如
seen.add(s.strip().lower()),否则"ABC"和"abc"会被视为不同元素
什么情况下 set 反而更慢或不适用?
小数据量(比如 len(lst) )时,<code>set 的哈希计算和内存分配开销可能抵消优势;另外这些场景不适合直接换 set:
- 需要保留首次/末次出现位置:得配合
dict记录索引,或用collections.OrderedDict(Python 3.7+ 普通dict已保序) - 元素本身不可哈希(如含嵌套
list的结构):可考虑用frozenset包装子结构,或序列化为json.dumps(item, sort_keys=True)后哈希 - 内存极度受限且只查一次:构建
set本身要额外内存,不如直接线性扫一遍
真正影响性能的往往不是“用不用 set”,而是“在哪儿建、建几次、怎么更新”。一个被反复重建的 set,比一个静态 list 还慢。


















