-
-
Notifications
You must be signed in to change notification settings - Fork 32k
bpo-4356: Add key function support to the bisect module #20556
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
2d1a404
9c9b275
5f2e4e5
92c40cb
bdfc074
5e3e5b9
899767c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -111,8 +111,6 @@ howto/urllib2,,:password,"""joe:[email protected]""" | |
library/ast,,:upper,lower:upper | ||
library/ast,,:step,lower:upper:step | ||
library/audioop,,:ipos,"# factor = audioop.findfactor(in_test[ipos*2:ipos*2+len(out_test)]," | ||
library/bisect,32,:hi,all(val >= x for val in a[i:hi]) | ||
library/bisect,42,:hi,all(val > x for val in a[i:hi]) | ||
library/configparser,,:home,my_dir: ${Common:home_dir}/twosheds | ||
library/configparser,,:option,${section:option} | ||
library/configparser,,:path,python_dir: ${Frameworks:path}/Python/Versions/${Frameworks:Python} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,22 @@ | ||
"""Bisection algorithms.""" | ||
|
||
def insort_right(a, x, lo=0, hi=None): | ||
|
||
def insort_right(a, x, lo=0, hi=None, *, key=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) | ||
if key is None: | ||
lo = bisect_right(a, x, lo, hi) | ||
else: | ||
lo = bisect_right(a, key(x), lo, hi, key=key) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I find suspicious that
Is this on purpose? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I recall the discussion in the other PR whether the "searched for item" should be an argument to It's a bit clearer in the case of Perhaps it's easier to disambiguate in the docs by mentioning how the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the API is correct in that it supports typical usage patterns. insort() will insert entire records and bisect() will scan the key field for the first match in a range at or above the key value. In SQL, the pattern would look like this:
In Python, the example would look like this:
If bisect() required an entire record as an input, it would preclude the ability to do searches like like this. Here's another example that we would want to support:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll echo what Raymond explained. It would be more useful to a library like sortedcontainers if the argument to bisect was the field value rather than the record. After all, the key function can be applied to the record to get the field value if need be. And there are many cases where constructing the record may be expensive or impossible just to determine rank within a list. The field value API is compatible with having the record and key function but not the other way around. The SortedKeyList data type provides both |
||
a.insert(lo, x) | ||
|
||
def bisect_right(a, x, lo=0, hi=None): | ||
|
||
def bisect_right(a, x, lo=0, hi=None, *, key=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 | ||
|
@@ -27,14 +31,26 @@ def bisect_right(a, x, lo=0, hi=None): | |
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 | ||
# Note, the comparison uses "<" to match the | ||
# __lt__() logic in list.sort() and in heapq. | ||
if key is None: | ||
while lo < hi: | ||
mid = (lo + hi) // 2 | ||
if x < a[mid]: | ||
hi = mid | ||
else: | ||
lo = mid + 1 | ||
else: | ||
while lo < hi: | ||
mid = (lo + hi) // 2 | ||
if x < key(a[mid]): | ||
hi = mid | ||
else: | ||
lo = mid + 1 | ||
return lo | ||
|
||
def insort_left(a, x, lo=0, hi=None): | ||
|
||
def insort_left(a, x, lo=0, hi=None, *, key=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. | ||
|
@@ -43,11 +59,13 @@ def insort_left(a, x, lo=0, hi=None): | |
slice of a to be searched. | ||
""" | ||
|
||
lo = bisect_left(a, x, lo, hi) | ||
if key is None: | ||
lo = bisect_left(a, x, lo, hi) | ||
else: | ||
lo = bisect_left(a, key(x), lo, hi, key=key) | ||
a.insert(lo, x) | ||
|
||
|
||
def bisect_left(a, x, lo=0, hi=None): | ||
def bisect_left(a, x, lo=0, hi=None, *, key=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 | ||
|
@@ -62,13 +80,25 @@ def bisect_left(a, x, lo=0, hi=None): | |
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 | ||
# Note, the comparison uses "<" to match the | ||
# __lt__() logic in list.sort() and in heapq. | ||
if key is None: | ||
while lo < hi: | ||
mid = (lo + hi) // 2 | ||
if a[mid] < x: | ||
lo = mid + 1 | ||
else: | ||
hi = mid | ||
else: | ||
while lo < hi: | ||
mid = (lo + hi) // 2 | ||
if key(a[mid]) < x: | ||
lo = mid + 1 | ||
else: | ||
hi = mid | ||
return lo | ||
|
||
|
||
# Overwrite above definitions with a fast C implementation | ||
try: | ||
from _bisect import * | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Add a key function to the bisect module. |
Uh oh!
There was an error while loading. Please reload this page.