blob: bcbcb075d87355974bbe6ca589dc60ef7ba0690c [file] [log] [blame]
Georg Brandl116aa622007-08-15 14:28:22 +00001:mod:`bisect` --- Array bisection algorithm
2===========================================
3
4.. module:: bisect
5 :synopsis: Array bisection algorithms for binary searching.
6.. sectionauthor:: Fred L. Drake, Jr. <fdrake@acm.org>
Christian Heimes5b5e81c2007-12-31 16:14:33 +00007.. example based on the PyModules FAQ entry by Aaron Watters <arw@pythonpros.com>
Georg Brandl116aa622007-08-15 14:28:22 +00008
9This module provides support for maintaining a list in sorted order without
10having to sort the list after each insertion. For long lists of items with
11expensive comparison operations, this can be an improvement over the more common
12approach. The module is called :mod:`bisect` because it uses a basic bisection
13algorithm to do its work. The source code may be most useful as a working
14example of the algorithm (the boundary conditions are already right!).
15
16The following functions are provided:
17
18
Georg Brandl0d8f0732009-04-05 22:20:44 +000019.. function:: bisect_left(a, x, lo=0, hi=len(a))
Georg Brandl116aa622007-08-15 14:28:22 +000020
Georg Brandl0d8f0732009-04-05 22:20:44 +000021 Locate the proper insertion point for *x* in *a* to maintain sorted order.
22 The parameters *lo* and *hi* may be used to specify a subset of the list
23 which should be considered; by default the entire list is used. If *x* is
24 already present in *a*, the insertion point will be before (to the left of)
25 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.
Georg Brandl116aa622007-08-15 14:28:22 +000027
Georg Brandl116aa622007-08-15 14:28:22 +000028
Georg Brandl0d8f0732009-04-05 22:20:44 +000029.. function:: bisect_right(a, x, lo=0, hi=len(a))
30 bisect(a, x, lo=0, hi=len(a))
Georg Brandl116aa622007-08-15 14:28:22 +000031
Georg Brandl0d8f0732009-04-05 22:20:44 +000032 Similar to :func:`bisect_left`, but returns an insertion point which comes
33 after (to the right of) any existing entries of *x* in *a*.
Georg Brandl116aa622007-08-15 14:28:22 +000034
Georg Brandl116aa622007-08-15 14:28:22 +000035
Georg Brandl0d8f0732009-04-05 22:20:44 +000036.. function:: insort_left(a, x, lo=0, hi=len(a))
Georg Brandl116aa622007-08-15 14:28:22 +000037
Georg Brandl0d8f0732009-04-05 22:20:44 +000038 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.
Georg Brandl116aa622007-08-15 14:28:22 +000041
Raymond Hettinger87c9d6c2010-08-07 07:36:55 +000042 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
Georg Brandl116aa622007-08-15 14:28:22 +000045
Georg Brandl0d8f0732009-04-05 22:20:44 +000046.. function:: insort_right(a, x, lo=0, hi=len(a))
47 insort(a, x, lo=0, hi=len(a))
Georg Brandl116aa622007-08-15 14:28:22 +000048
Georg Brandl0d8f0732009-04-05 22:20:44 +000049 Similar to :func:`insort_left`, but inserting *x* in *a* after any existing
50 entries of *x*.
Georg Brandl116aa622007-08-15 14:28:22 +000051
Raymond Hettinger87c9d6c2010-08-07 07:36:55 +000052 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.
Georg Brandl116aa622007-08-15 14:28:22 +000054
Raymond Hettinger87c9d6c2010-08-07 07:36:55 +000055Searching Sorted Lists
56----------------------
57
58The above :func:`bisect` functions are useful for finding insertion points, but
59can be tricky or awkward to use for common searching tasks. The following three
60functions show how to transform them into the standard lookups for sorted
61lists::
62
63 def find(a, key):
64 '''Find item with a key-value equal to 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:
70 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 with a key-value less-than or equal to key.
75 Raise ValueError if no such item exists.
76 If multiple key-values are equal, return the leftmost.
77
78 '''
79 i = bisect_left(a, key)
80 if i < len(a) and a[i] == key:
81 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 with a key-value greater-than or equal to key.
88 Raise ValueError if no such item exists.
89 If multiple key-values are equal, return the leftmost.
90
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]
96
97Other Examples
98--------------
Georg Brandl116aa622007-08-15 14:28:22 +000099
100.. _bisect-example:
101
102The :func:`bisect` function is generally useful for categorizing numeric data.
103This 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
Christian Heimesfe337bf2008-03-23 21:54:12 +0000105is a 'B', etc.
Georg Brandl116aa622007-08-15 14:28:22 +0000106
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)]
112 ...
113 >>> grade(66)
114 'C'
115 >>> map(grade, [33, 99, 77, 44, 12, 88])
116 ['E', 'A', 'B', 'D', 'F', 'A']
117
Raymond Hettingere046d2a2009-06-11 22:01:24 +0000118Unlike the :func:`sorted` function, it does not make sense for the :func:`bisect`
119functions to have *key* or *reversed* arguments because that would lead to an
120inefficent design (successive calls to bisect functions would not "remember"
121all of the previous key lookups).
Georg Brandl116aa622007-08-15 14:28:22 +0000122
Raymond Hettingere046d2a2009-06-11 22:01:24 +0000123Instead, it is better to search a list of precomputed keys to find the index
124of the record in question::
125
126 >>> data = [('red', 5), ('blue', 1), ('yellow', 8), ('black', 0)]
Raymond Hettinger27352a52009-06-11 22:06:06 +0000127 >>> data.sort(key=lambda r: r[1])
128 >>> keys = [r[1] for r in data] # precomputed list of keys
Raymond Hettingere046d2a2009-06-11 22:01:24 +0000129 >>> data[bisect_left(keys, 0)]
130 ('black', 0)
131 >>> data[bisect_left(keys, 1)]
132 ('blue', 1)
133 >>> data[bisect_left(keys, 5)]
134 ('red', 5)
135 >>> data[bisect_left(keys, 8)]
136 ('yellow', 8)
Raymond Hettinger87c9d6c2010-08-07 07:36:55 +0000137
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.