为何SortedList包含的元素用in查找失败,转普通list却可找到?
两种列表in查询结果存在差异的原因
普通列表的__contains__实现逻辑是全量遍历逐一做相等比较,只要列表中存在和目标完全相等的对象就会返回True,和元素的排序规则无关。
SortedList的__contains__基于二分查找实现:首先依靠自定义类的排序比较方法(__lt__等)定位目标元素的可能位置,仅在定位到的位置做一次相等判断。你遇到的场景中两个元素的排序值相等,二分查找会直接停在第一个排序值匹配的位置(索引38),不会继续向后扫描排序值相同的其他元素,因此对比到的是和目标不相等的元素,最终返回False。remove方法报错的原因和上述逻辑一致:该方法同样依赖二分查找定位元素位置,无法定位到排序值相等区间内的目标元素。
可行解决方案
方案1:指定排序key补全全序逻辑(推荐,侵入性最低)
SortedContainers的SortedList初始化支持传入key参数,你可以直接在构造实例时将排序规则设置为「业务排序字段+唯一标识」,既不修改原有自定义类的代码,也能保证所有元素的排序顺序唯一确定,不会破坏二分查找逻辑:
from sortedcontainers import SortedList # 此处用id(x)作为唯一标识,也可替换为自定义类的唯一属性如uuid等 sorted_list = SortedList(key=lambda x: (x.sort_key, id(x)))
方案2:修改自定义类的比较方法补全全序
如果所有该类的实例排序都需要固定顺序,你可以直接修改自定义类的比较逻辑,排序值相等时用唯一标识区分顺序:
import abc from functools import total_ordering @total_ordering class CustomClass(abc.ABC): def __init__(self, sort_key): self.sort_key = sort_key self._unique_id = id(self) # 也可替换为自定义的唯一字段 def __lt__(self, other): if self.sort_key == other.sort_key: return self._unique_id < other._unique_id return self.sort_key < other.sort_key def __eq__(self, other): # 相等判断根据你的业务逻辑实现即可,不需要和排序逻辑绑定 return isinstance(other, CustomClass) and self._unique_id == other._unique_id
方案3:保留现有排序逻辑,改用遍历操作
如果业务场景确实要求排序值相等的元素顺序任意,你可以放弃SortedList自带的O(log n)相等判断/删除方法,改用O(n)的遍历操作实现需求:
- 存在性判断直接沿用你已验证的写法:
custom_class in list(sorted_list) - 删除元素可自行遍历定位后调用
del删除:
target = custom_class for idx, item in enumerate(sorted_list): if item == target: del sorted_list[idx] break else: raise ValueError(f"{target} not in SortedList")
内容的提问来源于stack exchange,提问作者C Hecht
相关产品推荐
相关产品推荐

