为何Python用set()去重字典时报TypeError?如何高效保序去重?
为什么Python字典不可哈希?如何高效去除列表中重复字典并保留顺序?
一、字典不可哈希的原因
Python中,一个对象能被哈希(即可以作为set的元素或dict的键)必须满足两个核心条件:
- 不可变性:对象的内容不能被修改;
- 哈希值稳定:对象的
__hash__()方法必须返回固定不变的值,无论何时调用。
而字典是可变容器——你可以随时添加、删除或修改它的键值对。如果允许字典被哈希,当你修改字典内容后,它的哈希值会随之改变,这会导致依赖哈希的数据结构(比如set)出现逻辑混乱:比如你把字典加入set后修改它,set将无法再定位到这个元素,破坏了集合的唯一性约束。因此Python直接将字典标记为不可哈希类型,禁止它作为set元素或dict键。
二、去除重复字典并保留顺序的高效方法
Python 3.7+的内置dict会保留插入顺序,利用这个特性可以实现O(n)时间复杂度的高效去重,以下是几种常用方案:
1. 利用唯一标识键(最快,适用于有唯一键的场景)
如果你的字典有天然的唯一标识(比如示例中的id字段),直接用这个键作为字典的键来去重:
items = [ {'id': 1, 'name': 'Alice'}, {'id': 2, 'name': 'Bob'}, {'id': 1, 'name': 'Alice'} ] unique_dict = {d['id']: d for d in items} result = list(unique_dict.values()) print(result)
输出:
[{'id': 1, 'name': 'Alice'}, {'id': 2, 'name': 'Bob'}]
2. 无唯一键时,转成可哈希的元组(通用方案)
如果字典没有唯一键,将字典的键值对转成排序后的元组(确保相同内容的字典生成相同的元组),再用字典推导式去重:
items = [ {'id': 1, 'name': 'Alice'}, {'id': 2, 'name': 'Bob'}, {'id': 1, 'name': 'Alice'} ] # 排序键值对是为了避免因键的顺序不同导致元组不同 unique_dict = {tuple(sorted(d.items())): d for d in items} result = list(unique_dict.values()) print(result)
如果你的字典键的顺序固定(比如所有相同内容的字典键顺序一致),可以省略sorted(),直接用tuple(d.items()),效率会更高。
3. 手动维护已见集合(可读性强)
遍历列表时维护一个存储已见哈希键的集合,只添加未出现过的字典:
items = [ {'id': 1, 'name': 'Alice'}, {'id': 2, 'name': 'Bob'}, {'id': 1, 'name': 'Alice'} ] seen = set() result = [] for d in items: key = tuple(sorted(d.items())) if key not in seen: seen.add(key) result.append(d) print(result)
这个方法和字典推导式效率相当,适合需要更细粒度控制的场景。
内容的提问来源于stack exchange,提问作者user32747404
相关产品推荐
相关产品推荐

