python中的集合(set)给列表去重
使用集合(set)给列表去重的核心原理是利用集合的“元素唯一性”特性自动过滤重复项。但需注意:直接转集合会丢失原始顺序;若需保留顺序,应结合字典(dict.fromkeys())或辅助集合实现。以下是具体方法:
一、基础去重方法
1. 直接转集合(不保序,最快)
- 原理:集合天然不允许重复元素,将列表转为集合会自动去重。
- 代码示例:
nums = unique = list(set(nums)) print(unique) # 输出:(顺序随机,**不保证原顺序**) - 适用场景:无需保留原始顺序时(如统计唯一值、去重后直接排序等)。
- 性能:时间复杂度O(n),是所有方法中最快的。
2. 保序去重(推荐方法)
(1) 使用dict.fromkeys()(Python 3.7+)
- 原理:Python 3.7+ 的字典默认保持插入顺序,用列表元素作键可同时去重并保序。
- 代码示例:
nums = unique = list(dict.fromkeys(nums)) print(unique) # 输出:(**保留首次出现顺序**) - 优势:代码简洁、性能高(O(n)),是官方推荐的保序去重方案。
(2) 辅助集合 + 循环(通用兼容)
- 原理:遍历原列表,用集合记录已出现元素,仅添加新元素到结果列表。
- 代码示例:
nums = seen = set() unique = [x for x in nums if x not in seen and not seen.add(x)] print(unique) # 输出: - 适用场景:需兼容旧版 Python(<3.7)或需自定义去重逻辑时。
二、关键注意事项
1.元素必须可哈希
- 集合要求元素是可哈希的不可变对象(如数字、字符串、元组)。
- 不可直接处理列表/字典等可变对象,需先转为可哈希类型:
# 错误示例:列表不可哈希 # data = [, , ] # list(set(data)) # 报错:TypeError: unhashable type: 'list' # 正确做法:转为元组 data = [, , ] unique = [list(t) for t in set(tuple(x) for x in data)] print(unique) # 输出:[, ] - 自定义对象需实现
__hash__和__eq__方法。
2. 顺序问题
set()去重不保留顺序:不同 Python 版本/运行环境结果顺序可能不同。- 保序方法的选择:
- 优先用
dict.fromkeys()(Python 3.7+)。 - 旧版本可用
collections.OrderedDict:from collections import OrderedDict unique = list(OrderedDict.fromkeys(nums))
- 优先用
3. 性能对比
| 方法 | 是否保序 | 时间复杂度 | 适用场景 |
|---|---|---|---|
list(set(lst)) | ❌ | O(n) | 无需顺序,速度最快 |
list(dict.fromkeys(lst)) | ✅ | O(n) | 需保序的常规场景 |
| 循环 + 辅助集合 | ✅ | O(n) | 需自定义逻辑或兼容旧版本 |
列表推导式(if x not in) | ✅ | O(n²) | 小数据量,避免用于大数据集 |
大数据量时,O(n²) 方法(如列表推导式)性能显著劣于 O(n) 方法。
三、复杂场景处理
1. 按对象属性去重
- 场景:列表元素为字典/对象,需根据特定字段去重。
- 解决方案:用字段值作为唯一标识,结合辅助集合:
data = [{"id": 1, "name": "A"}, {"id": 1, "name": "B"}, {"id": 2, "name": "C"}] seen = set() unique = [x for x in data if x["id"] not in seen and not seen.add(x["id"])] print(unique) # 输出:[{'id': 1, 'name': 'A'}, {'id': 2, 'name': 'C'}]
2. 大数据量去重
- 内存优化:流式处理避免一次性加载全部数据。
def stream_deduplicate(iterable): seen = set() for item in iterable: if item not in seen: seen.add(item) yield item # 用法:unique = list(stream_deduplicate(large_data_stream))
总结
- 无需保序:直接用
list(set(original_list)),速度最快。 - 需要保序:优先用
list(dict.fromkeys(original_list))(Python 3.7+),简洁高效。 - 元素不可哈希:先转换为可哈希类型(如元组),再用集合去重。
- 性能关键点:避免在循环中使用
if x not in list(O(n²)),必须用集合辅助判断(O(1))。
以上方法均不修改原列表,而是返回新列表。若需原地去重,需结合切片赋值:
original_list[:] = list(dict.fromkeys(original_list))。
