list.sort和sorted以及bisect

# 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]])

posted @ 2020-06-16 19:08  怀心抱素  阅读(327)  评论(0编辑  收藏  举报