Python中的序列类型(二)

list.sort 方法和内置的 sorted 函数

list.sort

list 定义了一个排序方法 list.sort
,这个方法会就地排序列表,而不会将原列表复制排序生成新的列表。这也是其返回值为 None的原因,提示你这个方法不会新建列表

Python 风格:一个函数或方法对对象就地进行改动,其返回值为 None,好让调用者知道传入参数发生了变化。

从 python3.4 开始删除了 list.sort 方法,只能使用 sorted 创建一个新的有序序列

内置 sorted函数:

用法:sorted(iterable)

接受任何可迭代对象,其与 list.sort 不同,会将原对象复制一份,对复制进行排序,返回这个排序后的复制内容。

list.sortsorted 函数均可接受两个关键字参数:reverse 和 key

reverse:默认值为False,即升序排列,如果设置为 True,则按照降序排列

key: 传入的是func,以该 func 作用在对象元素后的值作为排序依据进行排序,但不改变对象元素。

>>> l = ['a', 'C', 'm', 'd', 'B']
>>> l.sort(key=lambda x: x.lower(), reverse=True)
>>> l
['m', 'd', 'C', 'B', 'a']

list.sortsorted 背后的排序算法是 Timsort,他是稳定的,何为稳定,看下面例子:

>>> fruits=['grape', 'raspberry', 'apple', 'banana']
>>> sorted(fruits, key=len)
['grape', 'apple', 'banana', 'raspberry']
>>> sorted(fruits, key=len, reverse=True)
['raspberry', 'banana', 'grape', 'apple']

排序方法相反,一顺一逆,为何结果并不完全相反,这就是排序稳定,当两个元素比不出大小,他们的相对位置是固定的,与原来列表相同。

bisect

bisect 模块有两个主要函数 bisect 和 insort,两者都利用二分查找算法在有序序列查找和插入元素。

bisect(haystack, needle) 函数在干草垛(haystack)里搜索针(needle)的位置,该位置满足的条件是:将 needle 插入这个位置后,haystack 还能保持升序,也就是这个函数返回的位置前面的值,都小于或等于 needle 的值,haystack 必须有序。

可以先用 bisect(haystack, needle) 查找位置index,之后用 haystack.insert(index, needle) 插入新值。也可以使用 insort 来一步到位

def ch2_17():
    """
    在haystack中打印出每个needle应属的位置
    """

    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_fom = '{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_fom.format(needle, position, offset))

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

也可以利用 bisect 建立索引,比如将分数和等级对应起来:

def grade(score, scores = [60, 70, 80, 90], ranks = 'FDCBA'):
    i = bisect.bisect(scores, score)
    return ranks[i]

l = [random.randint(50, 100) for x in range(10)]
print(l)
print(list(map(grade, l)))
[91, 55, 87, 66, 55, 86, 93, 61, 100, 68]
['A', 'F', 'B', 'D', 'F', 'B', 'A', 'D', 'A', 'D']

数组

列表很灵活简单,但在某些情况下其不是最好选择,比如当我要存储一百万个随机浮点数时,数组(array)会是更好的选择,因为数组背后存的并不是浮 float 对象,而是数字的机器翻译,也就是字节表示。

数组支持列表的所有跟可变序列有关的操作:pop、extend、insert,也支持存入文件 tofile 和从文件读取 fromfile

from array import array
from random import random

floats = array('d', [random() for x in range(10**7)])
with open('floats.bin', 'wb') as fp:
    floats.tofile(fp)

floats2 = array('d')
with open('floats.bin', 'rb') as fp:
    floats2.fromfile(fp)

内存视图

numpy

deque

当我们在对表使用 pop(index) 删除其前面的元素时, 被删除元素的后面所有元素均要移动,所以会很耗时。

这时可以使用 deque 双向队列,其具有:

  • 线程安全

  • 可以快速从两端添加或删除元素

  • 创建 deque 对象时可以指定对象长度,这样当队列满员时向首尾添加元素,会删除过期的部分

>>> from collections import deque
>>> dq = deque(range(10), maxlen = 10)
>>> dq
deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)
>>> dq.rotate(3)
>>> dq
deque([7, 8, 9, 0, 1, 2, 3, 4, 5, 6], maxlen=10)
>>> dq.rotate(-4)
>>> dq
deque([1, 2, 3, 4, 5, 6, 7, 8, 9, 0], maxlen=10)
>>> dq.extend([10, 20, 30, 40])
>>> dq
deque([5, 6, 7, 8, 9, 0, 10, 20, 30, 40], maxlen=10)
>>> dq.extendleft([50, 60])
>>> dq
deque([60, 50, 5, 6, 7, 8, 9, 0, 10, 20], maxlen=10)

如上,deque 支持 rotate(steps) 方法,当 steps > 0 时,序列中所有元素会向右移动 steps 位,最右边 steps 个元素将出现在序列左边,steps < 0 时相反。

下图是 list 与 deque 的方法对比:

[图片上传失败...(image-cab70f-1544191699167)]

你可能感兴趣的:(Python中的序列类型(二))