The usage of bisect_left, bisect_right, bisect, the difference is based on source code analysis

bisect_left(*args, **kwargs)

Inserts a number into an array and returns the position where it should be inserted.
If this number does not exist in this array, return the index of the first number larger than this number.
If this number exists, return the minimum value of the position of this number in the array (that is, the leftmost index)

Case 1: This number does not exist in the array

arr = [1, 3, 3, 5, 6, 6, 7, 9, 11]

# 在已排序的列表中查找元素 6 的插入位置
index = bisect_left(arr, 5.5)

print(f"Insert 6 at index {
      
      index} to maintain sorted order.")

Results of the:

Insert 6 at index 4 to maintain sorted order.

We find the first number 6 that is greater than 5.5 and output 4

Case 2: This number exists in the array

Let’s modify the code and find the position of 6

from bisect import bisect_left, bisect, bisect_right

arr = [1, 3, 3, 5, 6, 6, 7, 9, 11]

# 在已排序的列表中查找元素 6 的插入位置
index = bisect_left(arr, 6)

print(f"Insert 6 at index {
      
      index} to maintain sorted order.")

Results of the:

Insert 6 at index 4 to maintain sorted order.

We found it was still 4

bisect_right(*args, **kwargs)

Inserts a number into an array and returns the position where it should be inserted.
Function: Returns the index of the first number larger than this number

Case 1: This number does not exist in the array

from bisect import bisect_left, bisect, bisect_right

arr = [1, 3, 3, 5, 6, 6, 7, 9, 11]

# 在已排序的列表中查找元素 6 的插入位置

index = bisect_right(arr, 6.5)

print(f"Insert 6 at index {
      
      index} to maintain sorted order.")

Results of the:

Insert 6 at index 6 to maintain sorted order.

The position of the number 7 is output

Case 2: This number exists in the array

from bisect import bisect_left, bisect, bisect_right

arr = [1, 3, 3, 5, 6, 6, 7, 9, 11]

# 在已排序的列表中查找元素 6 的插入位置

index = bisect_right(arr, 6)

print(f"Insert 6 at index {
      
      index} to maintain sorted order.")

Results of the:

Insert 6 at index 6 to maintain sorted order.

The position of the number 7 is output

Compare bisect_left and bisect_right

Similarity:
When the second parameter number x is not in the first parameter array arr, both will return the position of the first number in arr that is larger than x.

The difference:
when x exists in arr, bisect_left will return the smallest index of x in arr, and bisect_right will return the position of the first number larger than x.

bisect()

We looked at the source code and found:
Insert image description here
bisect is bisect_right

Complete code

from bisect import bisect_left, bisect, bisect_right

arr = [1, 3, 3, 5, 6, 6, 7, 9, 11]

# 在已排序的列表中查找元素 6 的插入位置

index = bisect_right(arr, 6)

print(f"Insert 6 at index {
      
      index} to maintain sorted order.")

index = bisect(arr, 6)

print(f"Insert 6 at index {
      
      index} to maintain sorted order.")


index = bisect_left(arr, 6)

print(f"Insert 6 at index {
      
      index} to maintain sorted order.")

result:

Insert 6 at index 6 to maintain sorted order.
Insert 6 at index 6 to maintain sorted order.
Insert 6 at index 4 to maintain sorted order.

Source code analysis

Let’s first look at the source code of bisect_right

def bisect_right(a, x, lo=0, hi=None):
    """Return the index where to insert item x in list a, assuming a is sorted.

    The return value i is such that all e in a[:i] have e <= x, and all e in
    a[i:] have e > x.  So if x already appears in the list, a.insert(x) will
    insert just after the rightmost x already there.

    Optional args lo (default 0) and hi (default len(a)) bound the
    slice of a to be searched.
    """

    if lo < 0:
        raise ValueError('lo must be non-negative')
    if hi is None:
        hi = len(a)
    while lo < hi:
        mid = (lo+hi)//2
        # Use __lt__ to match the logic in list.sort() and in heapq
        if x < a[mid]: hi = mid
        else: lo = mid+1
    return lo

Source code of bisect_left

def bisect_left(a, x, lo=0, hi=None):
    """Return the index where to insert item x in list a, assuming a is sorted.

    The return value i is such that all e in a[:i] have e < x, and all e in
    a[i:] have e >= x.  So if x already appears in the list, a.insert(x) will
    insert just before the leftmost x already there.

    Optional args lo (default 0) and hi (default len(a)) bound the
    slice of a to be searched.
    """

    if lo < 0:
        raise ValueError('lo must be non-negative')
    if hi is None:
        hi = len(a)
    while lo < hi:
        mid = (lo+hi)//2
        # Use __lt__ to match the logic in list.sort() and in heapq
        if a[mid] < x: lo = mid+1
        else: hi = mid
    return lo

We observe that these two implementations mainly lie in the following two lines:
bisect_right:

        if x < a[mid]: hi = mid
        else: lo = mid+1

bisect_left:

        if a[mid] < x: lo = mid+1
        else: hi = mid

We observe that both pieces of source code will return lo, which is the left boundary, so we pay attention to the impact of these two lines of code on the left boundary:
In bisect_right, only when x=a[mid] or x>a[mid], lo will be updated to mid+1, so the final lo can only be the first index greater than x
in bisect_left. When a[mid] < x, lo will be updated to mid+1. At this time, what we want The index position must be on the right side of mid, so lo can be the position of the first occurrence of the same x; at the same time, we notice that when a[mid] >= x, hi=mid, which means that when lo gets the same number When it is the far left, the right endpoint of hi will actually be translated to the left, so lo can be the index of the first number greater than x in the array, or it can be the index of the first x on the left of the same x

Guess you like

Origin blog.csdn.net/qq_51118755/article/details/135071968