You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 00:37:03