44.. module :: bisect
55 :synopsis: Array bisection algorithms for binary searching.
66..
sectionauthor ::
Fred L. Drake, Jr. <[email protected] > 7+ .. sectionauthor :: Raymond Hettinger <python at rcn.com>
78.. example based on the PyModules FAQ entry by Aaron Watters <[email protected] >89
910 This module provides support for maintaining a list in sorted order without
@@ -18,102 +19,109 @@ The following functions are provided:
1819
1920.. function :: bisect_left(a, x, lo=0, hi=len(a))
2021
21- Locate the proper insertion point for *x * in *a * to maintain sorted order.
22+ Locate the insertion point for *x * in *a * to maintain sorted order.
2223 The parameters *lo * and *hi * may be used to specify a subset of the list
2324 which should be considered; by default the entire list is used. If *x * is
2425 already present in *a *, the insertion point will be before (to the left of)
2526 any existing entries. The return value is suitable for use as the first
26- parameter to ``list.insert() ``. This assumes that *a * is already sorted.
27+ parameter to ``list.insert() `` assuming that *a * is already sorted.
2728
29+ The returned insertion point *i * partitions the array *a * into two halves so
30+ that ``all(val < x for val in a[lo:i]) `` for the left side and
31+ ``all(val >= x for val in a[i:hi]) `` for the right side.
2832
2933.. function :: bisect_right(a, x, lo=0, hi=len(a))
3034 bisect(a, x, lo=0, hi=len(a))
3135
3236 Similar to :func: `bisect_left `, but returns an insertion point which comes
3337 after (to the right of) any existing entries of *x * in *a *.
3438
39+ The returned insertion point *i * partitions the array *a * into two halves so
40+ that ``all(val <= x for val in a[lo:i]) `` for the left side and
41+ ``all(val > x for val in a[i:hi]) `` for the right side.
3542
3643.. function :: insort_left(a, x, lo=0, hi=len(a))
3744
3845 Insert *x * in *a * in sorted order. This is equivalent to
39- ``a.insert(bisect.bisect_left(a, x, lo, hi), x) ``. This assumes that *a * is
40- already sorted.
41-
42- Also note that while the fast search step is O(log n), the slower insertion
43- step is O(n), so the overall operation is slow.
44-
46+ ``a.insert(bisect.bisect_left(a, x, lo, hi), x) `` assuming that *a * is
47+ already sorted. Keep in mind that the O(log n) search is dominated by
48+ the slow O(n) insertion step.
4549
4650.. function :: insort_right(a, x, lo=0, hi=len(a))
4751 insort(a, x, lo=0, hi=len(a))
4852
4953 Similar to :func: `insort_left `, but inserting *x * in *a * after any existing
5054 entries of *x *.
5155
52- Also note that while the fast search step is O(log n), the slower insertion
53- step is O(n), so the overall operation is slow.
56+ .. seealso ::
57+
58+ `SortedCollection recipe
59+ <http://code.activestate.com/recipes/577197-sortedcollection/> `_ that uses
60+ bisect to build a full-featured collection class with straight-forward search
61+ methods and support for a key-function. The keys are precomputed to save
62+ unnecessary calls to the key function during searches.
63+
5464
5565Searching Sorted Lists
5666----------------------
5767
58- The above :func: `bisect ` functions are useful for finding insertion points, but
59- can be tricky or awkward to use for common searching tasks. The following three
68+ The above :func: `bisect ` functions are useful for finding insertion points but
69+ can be tricky or awkward to use for common searching tasks. The following five
6070functions show how to transform them into the standard lookups for sorted
6171lists::
6272
63- def find(a, key):
64- '''Find leftmost item exact equal to the key.
65- Raise ValueError if no such item exists.
66-
67- '''
68- i = bisect_left(a, key)
69- if i < len(a) and a[i] == key:
73+ def index(a, x):
74+ 'Locate the leftmost value exactly equal to x'
75+ i = bisect_left(a, x)
76+ if i != len(a) and a[i] == x:
77+ return i
78+ raise ValueError
79+
80+ def find_lt(a, x):
81+ 'Find rightmost value less than x'
82+ i = bisect_left(a, x)
83+ if i:
84+ return a[i-1]
85+ raise ValueError
86+
87+ def find_le(a, x):
88+ 'Find rightmost value less than or equal to x'
89+ i = bisect_right(a, x)
90+ if i:
91+ return a[i-1]
92+ raise ValueError
93+
94+ def find_gt(a, x):
95+ 'Find leftmost value greater than x'
96+ i = bisect_right(a, x)
97+ if i != len(a):
7098 return a[i]
71- raise ValueError('No item found with key equal to: %r' % (key,))
72-
73- def find_le(a, key):
74- '''Find largest item less-than or equal to key.
75- Raise ValueError if no such item exists.
76- If multiple keys are equal, return the leftmost.
99+ raise ValueError
77100
78- '''
79- i = bisect_left(a, key)
80- if i < len(a) and a[i] == key:
101+ def find_ge(a, x):
102+ 'Find leftmost item greater than or equal to x'
103+ i = bisect_left(a, x)
104+ if i != len(a):
81105 return a[i]
82- if i == 0:
83- raise ValueError('No item found with key at or below: %r' % (key,))
84- return a[i-1]
85-
86- def find_ge(a, key):
87- '''Find smallest item greater-than or equal to key.
88- Raise ValueError if no such item exists.
89- If multiple keys are equal, return the leftmost.
106+ raise ValueError
90107
91- '''
92- i = bisect_left(a, key)
93- if i == len(a):
94- raise ValueError('No item found with key at or above: %r' % (key,))
95- return a[i]
96108
97109Other Examples
98110--------------
99111
100112.. _bisect-example :
101113
102- The :func: `bisect ` function is generally useful for categorizing numeric data.
103- This example uses :func: `bisect ` to look up a letter grade for an exam total
104- (say) based on a set of ordered numeric breakpoints: 85 and up is an 'A', 75..84
105- is a 'B', etc.
114+ The :func: `bisect ` function can be useful for numeric table lookups. This
115+ example uses :func: `bisect ` to look up a letter grade for an exam score (say)
116+ based on a set of ordered numeric breakpoints: 90 and up is an 'A', 80 to 89 is
117+ a 'B', and so on::
106118
107- >>> grades = " FEDCBA"
108- >>> breakpoints = [30 , 44 , 66 , 75 , 85 ]
109- >>> from bisect import bisect
110- >>> def grade (total ):
111- ... return grades[bisect(breakpoints, total)]
119+ >>> def grade(score, breakpoints=[60, 70, 80, 90], grades='FDCBA'):
120+ ... i = bisect(breakpoints, score)
121+ ... return grades[i]
112122 ...
113- >>> grade(66 )
114- 'C'
115- >>> map (grade, [33 , 99 , 77 , 44 , 12 , 88 ])
116- ['E', 'A', 'B', 'D', 'F', 'A']
123+ >>> [grade(score) for score in [33, 99, 77, 70, 89, 90, 100]]
124+ ['F', 'A', 'C', 'C', 'B', 'A', 'A']
117125
118126Unlike the :func: `sorted ` function, it does not make sense for the :func: `bisect `
119127functions to have *key * or *reversed * arguments because that would lead to an
@@ -135,9 +143,3 @@ of the record in question::
135143 >>> data[bisect_left(keys, 8)]
136144 ('yellow', 8)
137145
138- .. seealso ::
139-
140- `SortedCollection recipe
141- <http://code.activestate.com/recipes/577197-sortedcollection/> `_ that
142- encapsulates precomputed keys, allowing straight-forward insertion and
143- searching using a *key * function.
0 commit comments