原创《流畅的python》
bisect 模块包含两个主要函数, bisect 和 insort ,两个函数都利用二分查找算法来在有序序列中查找或插入元素。
并且是稳定排序
- 在有序序列中用 bisect 查找某个元素的插入位置
import bisect
import sys
HAYSTACK = [1, 4, 5, 6, 8, 12, 15, 20, 21, 23, 23, 26, 29, 30]
NEEDLES = [0, 1, 2, 5, 8, 10, 22, 23, 29, 30, 31]
ROW_FMT = '{0:2d} @ {1:2d} {2}{0:<2d}'
def demo(bisect_fn):
for needle in reversed(NEEDLES):
position = bisect_fn(HAYSTACK, needle) # 用特定的 bisect 函数来计算元素应该出现的位置
offset = position * ' |' # 利用该位置来算出需要几个分隔符号
print(ROW_FMT.format(needle, position, offset)) # 把元素和其应该出现的位置打印出来
if __name__ == '__main__':
if sys.argv[-1] == 'left': # 根据命令上最后一个参数来选用 bisect 函数
bisect_fn = bisect.bisect_left
else:
bisect_fn = bisect.bisect
print('DEMO:', bisect_fn.__name__) # 把选定的函数在抬头打印出来
print('haystack ->', ' '.join('%2d' % n for n in HAYSTACK))
demo(bisect_fn)
bisect 函数其实是 bisect_right 函数的别名,后者还有个姊妹函数叫 bisect_left 。它们的区别在于, bisect_left 返回的插入位置是原序列中跟被插入元素相等的元素的位置,也就是新元素会被放置于它相等的元素的前面,而 bisect_right 返回的则是跟它相等的元素之后的位置。
- 根据一个分数,找到它所对应的成绩
import bisect
def grade(score, breakpoints=[60, 70, 80, 90], grades='FDCBA'):
i = bisect.bisect(breakpoints, score)
# print(i)
return grades[i]
print([grade(score) for score in [33, 99, 77, 70, 89, 90, 100]])
- 用 bisect.insort 插入新元素
import bisect
import random
SIZE = 7
random.seed(1729)
my_list = list()
for i in range(SIZE):
new_item = random.randrange(SIZE*2)
bisect.insort(my_list, new_item)
print("%2d ->" % new_item, my_list)
以上方法不仅仅是对列表或者元组有效,还可以应用于几乎所有的序列类型
上。