list.sort 方法和内置的 sorted 函数
list.sort
list 定义了一个排序方法 list.sort
,这个方法会就地排序列表,而不会将原列表复制排序生成新的列表。这也是其返回值为 None的原因,提示你这个方法不会新建列表
Python 风格:一个函数或方法对对象就地进行改动,其返回值为 None,好让调用者知道传入参数发生了变化。
从 python3.4 开始删除了 list.sort
方法,只能使用 sorted
创建一个新的有序序列
内置 sorted
函数:
用法:sorted(iterable)
接受任何可迭代对象,其与 list.sort
不同,会将原对象复制一份,对复制进行排序,返回这个排序后的复制内容。
list.sort
和 sorted
函数均可接受两个关键字参数: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.sort
和 sorted
背后的排序算法是 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)]