如何让SortedSet添加重复元素时更新旧值的排序位置?
问题根因
SortedSet 遵循标准集合的通用设计:调用add()方法时,如果待加入元素和集合内已有元素判定为相等,会直接跳过本次添加操作,既不会替换原有元素,也不会调整集合顺序。
你的R类以person_id作为__eq__和__hash__的唯一判定依据,因此新传入的R(17, -67)会被判定为和集合内已有的R(17, 4)是重复元素,add()操作直接忽略新元素,集合自然不会变化。
另外你的代码里有一处笔误:不等于的魔术方法名是__ne__,你写成了__nq__,这个错误会导致不等于判断走默认逻辑,建议修正。
实现方案
SortedSet本身没有提供“重复元素自动替换”的配置项,要实现你要的效果,核心逻辑是添加新元素前,先把集合内和新元素相等的旧条目删掉,再插入新元素,插入过程会自动按排序规则放到正确位置。
方案1:轻量封装SortedSet
直接基于SortedSet做一层薄封装,实现支持更新的add逻辑:
from sortedcontainers import SortedSet class R(): def __hash__(self): return hash(self.person_id) def __eq__(self, other): return self.__class__ == other.__class__ and self.person_id == other.person_id # 修正原代码的方法名笔误 def __ne__(self, other): return not (self == other) def __lt__(self, other): # 保留原代码按value降序排序的逻辑 return other.value < self.value def __init__(self, person_id, value): self.person_id = person_id self.value = value def __repr__(self): return "person: %s (%s)" % (self.person_id, self.value) class UpdateableSortedSet: def __init__(self): self._data = SortedSet() def add(self, item): # 移除已存在的同id旧元素,元素不存在时discard不会抛错 self._data.discard(item) # 插入新元素,自动维护排序 self._data.add(item) def __repr__(self): return repr(self._data) # 测试代码 x = UpdateableSortedSet() x.add(R(13, 2)) x.add(R(17, 4)) x.add(R(11, 21)) x.add(R(7, -41)) x.add(R(17, -67)) print(x)
运行后输出完全符合预期:
SortedSet([person: 11 (21), person: 13 (2), person: 7 (-41), person: 17 (-67)])
方案2:字典+SortedList组合(适合需要按id快速查询的场景)
如果你除了有序去重的需求,还需要经常按person_id快速查找对象,可以用字典维护id到对象的映射,配合SortedList维护顺序,逻辑和方案1一致:
from sortedcontainers import SortedList class IndexedSortedSet: def __init__(self): self._sorted_data = SortedList() self._id_map = {} def add(self, item): if item.person_id in self._id_map: # 先删旧条目 old_item = self._id_map[item.person_id] self._sorted_data.remove(old_item) # 加新条目,更新索引 self._sorted_data.add(item) self._id_map[item.person_id] = item def get_by_id(self, person_id): return self._id_map.get(person_id) def __repr__(self): return repr(self._sorted_data)
注意事项
不要为了实现自动替换修改__eq__的判定逻辑(比如把value也加入相等判断),这样会导致同person_id不同value的对象被判定为不同元素,集合里会出现重复id的条目,违背去重的初始需求。
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

