Python语法速查: 15. 常用数据结构
本篇索引
(1)array
(2)bisect
(3)deque
(4)defaultdict
(5)namedtuple
(6)heapq
(7)itertools
(1)array
array模块定义一个数组类型:array,它与列表很相似,但它的内容仅限于单一类型。如果需要有效利用存储空间,那么就需要用到array模块。 例如,要存储1000万个整数,使用列表需要约160M内存,而使用array仅需40M内存,代价是array的操作比列表要慢一些。
array数组不适用于数字操作(如矩阵运算),要创建高效存储和计算的数组,可使用numpy扩展。
“+”运算符用于附加另一个数组的内容,“*”运算符用于重复附加一个数组。
● array(typecode [,initializer])
说明:
创建类型为typecode的数组,可取类型见下表。initializer是一个字符串或值列表,用于初始化数组中的值。
typecode取值类型
类型编码 | 描述 | 对应C类型 | 最小大小(字节数) |
---|---|---|---|
'c' | 8位字符 | Char | 1 |
'b' | 8位整型 | signed char | 1 |
'B' | 8位无符号整型 | unsigned char | 1 |
'u' | Unicode字符 | PY_UNICODE | 2或4 |
''h | 16位整型 | short | 2 |
'H' | 16位无符号整型 | unsigned short | 2 |
'i' | 整型 | int | 4或8(64位架构) |
'I' | 无符号整型 | unsigned int | 4或8(64位架构) |
'l' | 长整型 | long | 4或8(64位架构) |
'L' | 无符号长整型 | unsigned long | 4或8(64位架构) |
'f' | 单精度浮点数 | float | 4 |
'd' | 双精度浮点数 | double | 8 |
● array实例常用属性和方法
属性或方法 | 说明 |
---|---|
a.typecode | 属性,数组的编码字符。 |
a.itemsize | 属性,存储在数组中项的大小(以字节为单位)。 |
a.append(x) | 将x附加到数组末尾,若插入类型不匹配,则引发TypeError异常。 |
a.buffer_info() | 返回(address, length)元组,反映数组缓冲区的内存位置和长度。 |
a.byteswap() | 切换大端和小端的字节顺序,仅支持整型值。 |
a.count(x) | 返回数组中出现x的次数。 |
a.extend(b) | 将b附加到数组末尾,b也可以是一个数组。 |
a.fromfile(f, n) | 从文件对象f中读取n个项(二进制格式),并附加到数组末尾。若可读取的项少于n,则引发EOFError异常。 |
a.fromlist(list) | 将list中的项附加到数组末尾,list可以是可迭代对象。 |
a.fromstring(s) | 将字符串s中的项附加到数组末尾,其中s是一个由二进制值组成的字符串(与fromfile()中格式相同) |
a.index(x) | 返回x在数组中首次出现的位置索引,若未找到,则引发ValueError异常。 |
a.insert(i, x) | 在位置i前插入x。 |
a.pop([i]) | 从数组中删除项 i 并将其返回。如果i已被删除,则删除最后一个元素。 |
a.remove(x) | 从数组中删除第一个x,若未找到,则引发ValueError异常。 |
a.reverse() | 反转数组的顺序。 |
a.tofile(f) | 将所有项写入文件f。数据保存为本机二进制格式。 |
a.tolist() | 将数组转换为普通的值列表。 |
a.tostring() | 将数组转换为由二进制数据组成的字符串。 |
a.tounicode() | 将数组转换为Unicode字符串,如果数组类型不为'u',则引发ValueError异常。 |
(2)bisect
bisect模块可以在已排好顺序的列表中插入一个新数据,并使列表维持已排好的顺序,它使用二分法来执行大部分工作。
bisect的简单用例:
s = [1,3,5,7,9] bisect.insort(s, 6) print(s) # 结果为:[1,3,5,6,7,9]
bisect模块常用函数
属性或方法 | 说明 |
---|---|
insort(list, item [,low [,high]]) | 将item插入已排序好的列表list中。若item已在列表中,那么新项将插到现有项的右边。low和high是两边的要检查子集的边界。 |
insort_left(list, item [,low [,high]]) | 功能同上,只是若item已在列表中,那么新项将插到现有项的左边。 |
insort_right(list, item [,low [,high]]) | 同insort() |
bisect(list, item [,low [,high]]) | 计算如要将item插入到已排序好的的列表list中的插入索引点,并返回这个值。low和high是两边的要检查子集的边界。若item已在列表中,那么新计算的插入位置在现有项的右边。 |
bisect_left(list, item [,low [,high]]) | 功能同上,只是若item已在列表中,那么新计算的插入位置在现有项的左边。 |
bisect_right(list, item [,low [,high]]) | 同bisect() |
(3)deque
deque表示双端队列(发音:'deck'),要使用双端队列需要导入collections模块。
双端队列允许在队列的任一端插入或删除项,性能接近O(1)。而列表若要在最前端插入项,需要移动所有后续对象。
若为deque指定了maxlen参数,则向已满双端队列插入新项时,deque会自动在另一端删除一个数据来腾出空间。
● deque[iterable [,maxlen]])
说明:
iterable是可迭代对象,可用于初始化deque;maxlen表示双端队列允许的最大空间。
deque实例常用方法
属性或方法 | 说明 |
---|---|
d.append(x) | 将x添加到d的右端。 |
d.appendleft(x) | 将x添加到d的左端。 |
d.clear() | 从d中删除所有项。 |
d.extend(iterable) | 将iterable中的所有项添加到d的右端,以扩展d。 |
d.extendleft(iterable) | 将iterable中的所有项添加到d的左端,iterable中的项将按相反顺序出现在d中。 |
d.pop() | 返回并删除d右端的项。若d为空,则引发IndexError异常。 |
d.popleft() | 返回并删除d左端的项。若d为空,则引发IndexError异常。 |
d.remove(item) | 删除首次出现的item,若未找到匹配值,则引发ValueError异常。 |
d.rotate(n) | 将所有项向右旋转n步,若n为负值,则向左旋转项。 |
另外,deque实例也支持以下内置操作或内置函数:迭代、in
操作符、 []
下标操作、len(d)
、reversed(d)
、 copy.copy(d)
、copy.deepcopy(d)
。
对于下标操作,在头尾处的取出速度为 O(1),在队列中间处的取出速度退化为O(n)。
从Python3.5起,还支持__add__()
、__mul()__
、__imul()__
方法。
(4)defaultdict
要使用defaultdict需要导入collections模块。defaultdict与普通字典用法基本一样,只是在缺少键的处理上有不同。当索引不存在的键名时,将调用default_factory提供的函数来提供一个默认值,然后将该值保存为键的值。其余操作与内置dict()完全相同。
其实,普通的字典的setdefault()方法也能完成这一功能,只是setdefault()语句结构不是很清晰,且运行速度较慢。
● 初始化语法:
default([default_factory], ...)
用法示例,统计各个单词出现的位置并将其位置序列放入字典中。
from collections import defaultdict s = 'a b c a b c' word_list = s.split() # word_list值为:['a', 'b', 'c', 'a', 'b', 'c'] dd = defaultdict(list) for i, w in enumerate(word_list): dd[w].append(i) # 最终dd结果为:defaultdict(<class 'list'>, {'a': [0, 3], 'b': [1, 4], 'c': [2, 5]})
(5)namedtuple
namedtuple表示命名元组,要使用namedtuple需要导入collections模块。在命名元组中,可以使用属性名称来访问元组元素,可以动态增加新属性。缺点是比普通元组慢一点。
● 初始化语法:
namedtyple(typename, filednames [,verbose])
typename作为新创建的命名元组名称(它是tuple的子类),fieldnames是字符串形式的属性名称的列表,不能以下划线开头。fieldnames也可写成一个字符串,各属性间用空格或逗号分隔。verbose标记若设为True,将向标准输出端输出生成的类定义。
使用命名元组的简单示例:
from collections import namedtuple NewAddrPort = namedtuple('NewAddrPort', ['ipaddr', 'port']) a = NewAddrPort('127.0.0.1', 80) print(a.ipaddr, a.port) # 结果为:'127.0.0.1' 80 ipaddr, host = a # 本句可将命名元组a像普通元组那样解包展开。 isinstance(a, tuple) # 结果为:True
如果定义一个仅作为数据结构的对象,那可以用命名元组来替代:
class Square(object): def __init(self, l, w): self.l = l self.w = w # 可以用命名元组来替代: import collections Square = collections.namedtuple('Square', 'l w') nt = Square(10, 20)
使用命名元组的优点是:可以像实例那样来访问属性,如:nt.l、nt.w;也可以对nt像普通元组那样使用for语句和解包语句。
(6)heapq
heapq模块使用堆实现一个优先级队列。优先级队列能以任意顺序添加对象,并能随时找出最小的元素,它比列表的min方法要快得多。
heapq模块常用函数
函数 | 说明 |
---|---|
heapify(x) | 将列表x原地转换为堆。 |
heappop(heap) | 返回并删除heap中最小的项,若heap为空,则引发IndexError异常。 |
heappush(heap, item) | 将item添加到堆中。 |
heappushpop(heap, item) | 在一个操作中将item添加到堆并从heap中删除最小项。这比分别调用heappush()和heappop()更高效。 |
heapreplace(heap, item) | 返回并删除堆中最小的元素,并同时添加一个新item。新项的添加在获取返回值之后,因此返回值可能比item更大。若heap为空,则引发IndexError异常。 |
merge(s1, s2, ...) | 创建一个迭代器,将有序的迭代变量s1, s2等合并到一个有序序列中。 |
nlargest(n, iter [,key]) | 创建一个列表,包含iter中最大的n个项,最大项排在返回列表的前端。key是可选参数,接受一个输出参数并计算iter中每个项的比较键。 |
nsmallest(n, iter [,key]) | 创建一个列表,包含iter中最小的n个项,最小项排在返回列表的前端。key含义同上。 |
heap用法示例:
import heapq x = [1,9,2,8,3,7,4,6] heapq.heapify(x) # 本句运行后,x已变成优先级队列 print(x) >>> [1,3,2,6,8,7,4,9] # x已按堆的优先级排序好 heapq.heappop(x) >>> 1 heapq.heappop(x) >>> 2
(7)itertools
itertools模块包含创建高效迭代器的函数,可以用各种方式对数据执行循环操作。
itertools模块常用函数
函数 | 说明 |
---|---|
chain(iter1, iter2, ..., iterN) | 此函数创建一个新迭代器将所有入参迭代器链接起来,返回的迭代器从iter1的第1项开始,到iterN的最后一项。 |
chain.from_iterable(iterables) | 一个备用链构造函数。 |
combinations(iter, r) | 创建一个迭代器,返回iter中所有长度为r的子序列。例如:combinations([1,2,3], 2)生成的序列为:[1,2]、[1,3]、[2,3]。 |
count([n]) | 创建一个迭代器,生成从n开始的连续整数,如果忽略n则从0开始。如果超出了系统的最大正整数范围,则从系统最小负整数-1继续。 |
cycle(iter) | 创建一个迭代器,对iter中的元素反复执行循环操作,生成一个迭代器副本。 |
dropwhile(predicate, iter) | 创建一个迭代器,只要函数perdicate(item)为True,就丢弃iter中的项,若为False则存入此项到新迭代器。 |
filterfalse() | 创建一个迭代器,仅生成iter中predicate(item)为False的项,若predicate为None,将返回iter中所有计算为False的项。 |
groupby(iter, [,key]) | 创建一个迭代器,对iterable生成的连续项进行分组,在分组过程中会查找重复项。 |
islice(iter [,start], stop [,step]) | 创建一个迭代器,生成的项类似于切片返回值:iter[start:stop:step],但start, stop, step都不能使用负值。 |
permutations(iter [,r]) | 创建一个迭代器,返回iter中所有长度为r的序列,若省略r,那么序列长度与iter中的项数相同。 |
product(iter1, iter2, ..., iterN, [repeat=1]) | 创建一个迭代器,生成表示item1, item2等中的项的笛卡尔积的元组。repeaet指定重复生成序列的次数。 |
repeat(object [,times]) | 创建一个迭代器,重复生成object。times指定重复计数,如果未指定times,将无止尽地返回该对象。 |
starmap(func [,iter]) | 创建一个迭代器,生成值未func(*item),只有当iter生成的项适合用于这种调用函数的方式时,此函数才有效。 |
takewhile(predicate [,iter]) | 创建一个迭代器,深禅iter中predicate(item)未True的项,只要predicate计算未False,迭代就会立刻停止。 |
tee(iter [,n]) | 从iter创建n个独立的迭代器,创建的迭代器以n元组的形式返回,n的默认值为2。 |
迭代器使用的一些示例:
from itertools import * # 在数字0,1,...,10,9,8,...,1上无限循环 for i in cycle(chain(range(10), range(10,0-1))): print(i) # 创建a中的唯一项列表 a = [1,2,3,4,2,3,4,5] a.sort() b = [k for k,g in groupby(a)] # b = [1,2,3,4,5] # 对x和y中所有可能的值对进行组合迭代 x = [1,2,3] y = [10,11] for r in product(x,y): print(r) # 生成输出:(1,10), (1,11), (2,10), (2,11), (3,10), (3,11)