From 342ddad9d0b9acb0af0b4b8d2ae64e2380978ce3 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Fri, 17 Mar 2023 11:38:22 +0800 Subject: [PATCH] add `bisect` --- python/bisect.py | 72 ++++++++++++++++++++++++++++++++++++++++++++++ src/pocketpy.h | 1 + tests/70_bisect.py | 44 ++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+) create mode 100644 python/bisect.py create mode 100644 tests/70_bisect.py diff --git a/python/bisect.py b/python/bisect.py new file mode 100644 index 00000000..a0df9bc7 --- /dev/null +++ b/python/bisect.py @@ -0,0 +1,72 @@ +"""Bisection algorithms.""" + +def insort_right(a, x, lo=0, hi=None): + """Insert item x in list a, and keep it sorted assuming a is sorted. + + If x is already in a, insert it to the right of the rightmost x. + + Optional args lo (default 0) and hi (default len(a)) bound the + slice of a to be searched. + """ + + lo = bisect_right(a, x, lo, hi) + a.insert(lo, x) + +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 + if x < a[mid]: hi = mid + else: lo = mid+1 + return lo + +def insort_left(a, x, lo=0, hi=None): + """Insert item x in list a, and keep it sorted assuming a is sorted. + + If x is already in a, insert it to the left of the leftmost x. + + Optional args lo (default 0) and hi (default len(a)) bound the + slice of a to be searched. + """ + + lo = bisect_left(a, x, lo, hi) + a.insert(lo, x) + + +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 + if a[mid] < x: lo = mid+1 + else: hi = mid + return lo + +# Create aliases +bisect = bisect_right +insort = insort_right diff --git a/src/pocketpy.h b/src/pocketpy.h index 90f8d1ec..16fe3dfb 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -732,6 +732,7 @@ void VM::post_init(){ _lazy_modules["functools"] = kPythonLibs["functools"]; _lazy_modules["collections"] = kPythonLibs["collections"]; _lazy_modules["heapq"] = kPythonLibs["heapq"]; + _lazy_modules["bisect"] = kPythonLibs["bisect"]; CodeObject_ code = compile(kPythonLibs["builtins"], "", EXEC_MODE); this->_exec(code, this->builtins); diff --git a/tests/70_bisect.py b/tests/70_bisect.py new file mode 100644 index 00000000..c51dc3d2 --- /dev/null +++ b/tests/70_bisect.py @@ -0,0 +1,44 @@ +from bisect import bisect_left, bisect_right, insort_left, insort_right + +a = [1, 1, 2, 6, 7, 8, 16, 22] + +assert bisect_left(a, 23) == 8 # 23 does not exist in the list +assert bisect_left(a, 22) == 7 # 22 exists in the list +assert bisect_left(a, 0) == 0 # 0 does not exist in the list +assert bisect_left(a, 1) == 0 # 1 exists in the list +assert bisect_left(a, 5) == 3 # 5 does not exist in the list +assert bisect_left(a, 6) == 3 # 6 does exist in the list + +# test bisect_right +assert bisect_right(a, 23) == 8 # 23 does not exist in the list +assert bisect_right(a, 22) == 8 # 22 exists in the list +assert bisect_right(a, 0) == 0 # 0 does not exist in the list +assert bisect_right(a, 1) == 2 # 1 exists in the list +assert bisect_right(a, 5) == 3 # 5 does not exist in the list +assert bisect_right(a, 6) == 4 # 6 does exist in the list + +# test insort_left +insort_left(a, 23) +assert a == [1, 1, 2, 6, 7, 8, 16, 22, 23] + +insort_left(a, 0) +assert a == [0, 1, 1, 2, 6, 7, 8, 16, 22, 23] + +insort_left(a, 5) +assert a == [0, 1, 1, 2, 5, 6, 7, 8, 16, 22, 23] + +insort_left(a, 1) +assert a == [0, 1, 1, 1, 2, 5, 6, 7, 8, 16, 22, 23] + +# test insort_right +insort_right(a, 23) +assert a == [0, 1, 1, 1, 2, 5, 6, 7, 8, 16, 22, 23, 23] + +insort_right(a, 0) +assert a == [0, 0, 1, 1, 1, 2, 5, 6, 7, 8, 16, 22, 23, 23] + +insort_right(a, 5) +assert a == [0, 0, 1, 1, 1, 2, 5, 5, 6, 7, 8, 16, 22, 23, 23] + +insort_right(a, 1) +assert a == [0, 0, 1, 1, 1, 1, 2, 5, 5, 6, 7, 8, 16, 22, 23, 23] \ No newline at end of file