• 流畅的Python读书笔记(五)序列:序列的排序及管理


    流畅的Python读书笔记(四)序列:列表的排序及管理

    概述

    文章简单介绍了python中列表的排序list.sortsorted方法,主要讲解了管理有序序列的库bisect

    列表排序

    说到列表排序,对于刚学习Python的同学来说,很快就能想到list.sortsorted。下面只是简单再说明一下这两个函数。

    • list.sort(self, key=None, reverse=False)方法会就地排序列表,而不会创建原列表的一份拷贝,再排序。

    • sorted(iterable, key=None, reverse=False)方法会新建一个列表并返回,该对象已排好序。注意:①参数iterable可以接受任何形式的可迭代对象,甚至包括不可变序列或生成器。②不管sorted接受的是什么样的参数,最后都会返回一个列表,该列表包含了iterable中的所有元素。

    顺带一提的小知识:Python及Java7之后的标准库中的排序算法使用的都是TimSort算法。Timsort是一种混合、稳定高效的排序算法,源自合并排序和插入排序,旨在很好地处理多种真实数据。

    列表管理

    此处所说的列表管理,就是当我们向已经排好序的列表中增加元素后,仍然维持列表的有序性。

    管理有序序列很简单,已有现成的库可供我们使用——bisectbisect的底层算法为二分查找,比较简单,感兴趣可以去看看源码。

    bisect中主要包含两个函数bisect.bisectbisect.insort,前者返回将要插入元素应该插入的位置,后者直接插入要插入的元素。

    • bisect.bisect(a, x, lo=0, hi=None)

      • 参数介绍:a是要被排序的对象,x是要插入的元素,lo,hi是可选参数,分别表示搜索范围的边界。如果lo,hi为默认,则函数会将x应该插入的位置下标返回,搜索的范围是a[lo:hi],其中lo=0,hi=len(a)

      • 特殊情况:当要插入的元素事先已存在于a中时,bisect.bisect返回的下标应该是存在于a中的与x相等的元素下标的右侧,即返回值为a.index(x)+1.

      • 对特殊情况的解释:从bisect模块的源码中可以看出bisect.bisect函数有两个版本,一是bisect.bisect.bisect_left,另一个是bisect.bisect.bisect_right,这两个函数只是在处理特殊情况时有所不同,想必你也能猜到它们的区别,就是遇到特殊情况时,是返回a.index(x)还是a.index(x)+1

      # bisect模块中的代码,所以
      # bisect.bisect就是bisect.bisect_right
      # Create aliases
      bisect = bisect_right
      insort = insort_right
      
      • 1
      • 2
      • 3
      • 4
      • 5

    使用示例:

    import bisect
    import random
    
    random.seed(0) #设定种子,保证随机生成数可再现
    n = 10 #随机生成10个数,构成列表
    a = [random.randrange(10) for i in range(n)]
    a.sort() #先对列表进行排序(升序)
    print(a) 
    index = bisect.bisect(a, 6)
    print("要插入的位置:", index)
    index = bisect.bisect(a, 10)
    print("要插入的位置:", index)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    结果:注意,插入元素6时,原列表中有3个6,根据结果可以判断,返回的数值为最右侧6的下标加1.

    [0, 4, 4, 5, 6, 6, 6, 7, 7, 8]
    要插入的位置: 7
    要插入的位置: 10
    
    • 1
    • 2
    • 3
    • bisect.insort(a, x, lo=0, hi=None)

      • 参数介绍:参数与上面的bisect.bisect基本一致,不做介绍。唯一的区别就是insort是直接插入元素。

      • 遇到特殊情况(即有与x相等的元素位于a中时),处理方式与前面介绍的一致。只不过,insort方法会直接将元素插入。

      • 同样的insort()方法也有两个版本,insort_right,insort_left

      # Create aliases
      bisect = bisect_right
      insort = insort_right
      
      # insrot就是insort_right的别名
      
      • 1
      • 2
      • 3
      • 4
      • 5

    使用示例:

    import bisect
    import random
    
    random.seed(0) #设定种子,保证随机生成数可再现
    n = 10 #随机生成10个数,构成列表
    a = [random.randrange(10) for i in range(n)]
    a.sort() #先对列表进行排序(升序)
    print(a) 
    print("插入元素6,要插入的位置:", bisect.bisect(a, 6))
    bisect.insort(a, 6),
    print("插入元素后,列表变为:")
    print(a)
    
    
    print("插入元素10,要插入的位置:", bisect.bisect(a, 10))
    bisect.insort(a, 10)
    print("插入元素后,列表变为:")
    print(a)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    结果:

    [0, 4, 4, 5, 6, 6, 6, 7, 7, 8]
    插入元素6,要插入的位置: 7
    插入元素后,列表变为:
    [0, 4, 4, 5, 6, 6, 6, 6, 7, 7, 8]
    插入元素10,要插入的位置: 11
    插入元素后,列表变为:
    [0, 4, 4, 5, 6, 6, 6, 6, 7, 7, 8, 10]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    例题

    以下是流畅的Python书中给出的例子,可以拿来练练手,看看前面所讲的知识掌握了没有。拷贝代码,自行运行。以下代码演示了排序对象变化的过程。

    • 用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)
            offset = position * ' | '
            print(ROW_FMT.format(needle, position, offset))
    if __name__ == '__main__':
        if sys.argv[-1] == 'left':
            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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 用bisect.insort插入新元素
    import bisect
    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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    参考资料

    • 流畅的Python
  • 相关阅读:
    mybatis-plus 默认开启驼峰命名法导致获取不到值
    Linux运维常见故障排查方法及修复故障大全一部
    WiFi 四次握手&Omnipeek抓包
    Spring之IoC(容器配置、Spring坐标导入、获取bean)
    MySQL进阶学习
    795. 区间子数组个数
    基于沙猫群优化算法的线性规划求解matlab程序
    代码随想录二刷 |数组 | 螺旋矩阵II
    Linux(Centos)服务器探索ffmpeg笔记 (命令行、Nvidia硬件加速、GPU、CPU、CUDA、h264_nvenc、过滤器、加水印)
    JavaScript:实现JSON高亮代码块
  • 原文地址:https://blog.csdn.net/m0_52339560/article/details/126563817