# list.sort方法和内置函数sorted
# list.sort方法会就地排序列表,也就是说不会把原列表复制一份.这也是这个方法的返回值是None的原因,提醒你本方法不会新建一个列表.
# 在这种情况下返回None其实是Python的一个惯例: 如果一个函数或者方法对对象进行的是就地改动,那么它就应该返回None,好让调用者知道传入的参数发生了变动,并且并未产生新的对象.
# 与list.sort相反的是内置函数sorted(),它会新建一个列表作为返回值.这个方法可以接受任何形式的可迭代对象作为参数,甚至包括不可变序列或生成器.
# 而不管sorted接受的是怎样的参数,它最后都会返回一个列表.
# 不管是list.sort还是sorted函数,都有两个可选的关键字参数
# reverse: 如果被设定为True,被排序的序列里的元素会以降序输出,这个参数的默认值是False
# key: 一个只有一个参数的函数,这个函数会被用在序列里的每一个元素上,所产生的结果将是排序算法依赖的对比关键字.
# 比如说,在对一些字符串排序时,可以用key=str.lower来实现忽略大小写的排序,或者用key=len进行基于字符串长度的排序
# 这个参数的默认值是恒等函数,也就是默认用元素自己的值来排序.
# 下面通过几个小例子来看看这两个函数和它们的关键字参数
fruits = ["grape", "raspberry", "apple", "banana"]
print(sorted(fruits)) # 新建了一个按照字母排序的字符串列表
print(fruits) # 原列表没有变化
print(sorted(fruits, reverse=True)) # 按照字母降序排列
print(sorted(fruits, key=len)) # 新建一个按照长度排序的字符串列表.因为这个排序算法是稳定的,grape和apple的长度都是5,它们的相对位置跟在原来的列表里是一样的.
print(sorted(fruits, key=len, reverse=True)) # 按照长度降序排列,结果并不上上面那个结果的完全翻转,因为用到的排序算法是稳定的,也就是说在长度一样时,grape和apple的相对位置不会改变.
print(fruits.sort()) # 对原列表进行就地排序,返回值是None
print(fruits) # 此时fruits本身被排序
# 已排序的序列可以用来进行快速搜索,而标准库的bisect模块给我们提供了二分查找法.
# 用bisect来管理已排序的序列 bisect模块包含两个主要函数,bisect和insort,两个函数都利用二分查找法来在有序序列中查找和插入元素
# bisect(haystack, needle)在haystack里搜索needle的位置,该位置满足的条件是,把needle插入这个位置后,haystack还能保持升序.
# 也就是说这个函数返回的位置前面的值,都小于或等于needle的值.
# 可以使用bisect(haystack, needle)来查找位置index,再用haystack.insert(index, needle)来插入新值.但是也可以用insort来一步到位,并且后者的速度会快一点.
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)) # 把元素和其应该出现的位置打印出来
def grade(score, breakpoints=None, grades='FDCBA'):
# 讲分数与评级对应起来 60以下F,90以上A
breakpoints = [60, 70, 80, 90] if not breakpoints else breakpoints
i = bisect.bisect(breakpoints, score)
return grades[i]
# 用bisect.insort插入新的元素
# 排序很耗时,因此在得到一个有序序列之后,我们最好能够保持它的有序.bisect.insort就是为了这个而存在的
# insort(seq, item)把变量item插入到序列seq中,并能保持seq的升序顺序.
import random
SIZE = 7
random.seed(1729)
my_list = []
for i in range(SIZE):
new_item = random.randrange(SIZE*2)
bisect.insort(my_list, new_item)
print('%2d ->' % new_item, my_list)
"""
10 -> [10]
0 -> [0, 10]
6 -> [0, 6, 10]
8 -> [0, 6, 8, 10]
7 -> [0, 6, 7, 8, 10]
2 -> [0, 2, 6, 7, 8, 10]
10 -> [0, 2, 6, 7, 8, 10, 10]
"""
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)
"""
DEMO: bisect
haystack -> 1 4 5 6 8 12 15 20 21 23 23 26 29 30
31 @ 14 | | | | | | | | | | | | | |31
30 @ 14 | | | | | | | | | | | | | |30
29 @ 13 | | | | | | | | | | | | |29
23 @ 11 | | | | | | | | | | |23
22 @ 9 | | | | | | | | |22
10 @ 5 | | | | |10
8 @ 5 | | | | |8
5 @ 3 | | |5
2 @ 1 |2
1 @ 1 |1
0 @ 0 0
"""
print([grade(score) for score in [33, 99, 77, 70, 89, 90, 100]])