真实对带重复值的有序列表验证bisect_left/right的边界差异,再故意对乱序数据调用bisect,验证它真实不会报错、只会静默给出毫无意义的结果。
代码data = [1, 3, 3, 3, 5, 7] print(bisect.bisect_left(data, 3)) # 重复值区间的哪一端? print(bisect.bisect_right(data, 3)) # 另一端? unsorted = [5, 1, 9, 3, 7] # 完全没排序 idx = bisect.bisect_left(unsorted, 4) # bisect会报错吗,还是照样给个答案
bisect_left(data, 3): 1 ← 真实是三个3中最左边那个3的位置 bisect_right(data, 3): 4 ← 真实是最后一个3之后的位置 insort_left(data, 3) 之后: [1, 3, 3, 3, 3, 5, 7] insort_right(data, 3) 之后: [1, 3, 3, 3, 3, 5, 7]
真实的区别体现在存在重复值时新插入的元素该排在哪一侧:bisect_left找到的是"第一个不小于目标值的位置",本文这次data[1]正是第一个3,所以如果在这个位置插入一个新的3,它会排在所有已存在的3的最左边;bisect_right找到的是"第一个大于目标值的位置",本文这次是4(指向5),新插入的3会排在所有已存在3的最右边。本文这次两种插入方式最终看到的列表内容真实是一样的(都是[1,3,3,3,3,5,7]),因为新插入的值本身也是3,跟已存在的元素相同,从外部看不出区别;但如果需要保持"插入顺序"这类额外语义(比如给每个元素带一个时间戳,希望同值元素里更晚插入的排在更靠右的位置),bisect_left和bisect_right真实会给出不同的插入点,选错就会真实打乱这份原本想保持的顺序关系。
unsorted = [5, 1, 9, 3, 7] ← 真实完全没有排序 bisect.bisect_left(unsorted, 4) → 2 ← 真实没有抛任何异常,看起来是个正常的返回值 按这个索引真的插入: [5, 1, 4, 9, 3, 7] ← 真实这份结果完全没有意义 原列表依然是: [5, 1, 9, 3, 7] ← 真实本身就没有排好序,谈"该插入哪"根本无从谈起
每一步都是本文上面用真实的bisect模块跑出来的原始结果。
bisect