这次我们来说说python中的数据结构。当然了,不会讲很基础的内容。

用过python的都知道,python有着与其他语言很不一样的数据类型,像什么列表、元组、集合、字典之类。这些数据类型造就了python简单易用同时又很强大的特性。一般来说,我们会将python中的数据类型分为可变和不可变类型,可变的意思就是你可以修改像列表中的数据,不可变当然就是不能修改啦。还有一种分法是分为扁平类型和容器类型,其中扁平类型存放的是实际的值,包括str, bytes, bytearray,array.array这些,而容器类型存放的是数据值的引用,包括list,tuple,collections.deque这些。

既然是讲数据结构,我们来看看python中不经常用到的一些数据类型。

数组

没错,python是有数组类型的。当你有很大的数据需要处理的时候,它比列表更高效。如何创建一个数组?使用array.array。比如我们创建一万个随机浮点数。

from array import array
from random import random
# array中的第一个参数代表数据类型,比如float,char等。第二个参数为可迭代的数据。
# d代表双精度浮点类型
data = array('d', (random() for i in range(10**7)))
# 输出最后一个元素看看
print(data[-1])
0.5888905969627429
数组中提供了一些很有用的方法来处理数据,比如pop,insert,同时也有写入文件的tofile和读取的frombytes方法。
with open('data.bin', 'wb') as fp:
data.tofile(fp)

双端队列

学过数据结构的都知道队列,双端队列就是两边都可以进出的队列。python中的双端队列使用collections.deque表示。当然了你如果想用它来表示栈也是没问题的。append方法用来添加,pop方法用来弹出。怎么使用?

from collections import deque
data = deque(range(10), maxlen = 3)
print(data)
deque([7, 8, 9], maxlen=3)

如上所示,第一个参数为数据,第二个参数是队列的最大长度,如果不指定则默认为无限长。如果限制了长度,则增加数据会挤掉最先插入的数据。

data.append(3)
# 挤掉了7
print(data)
data.pop()
print(data)
deque([8, 9, 3], maxlen=3)
deque([8, 9], maxlen=3)

python中实现了堆排序。你可以用堆排序来查找一个序列中最大的或者最小的几个元素。比如我们有一个列表:

import heapq
nums = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2]
# 找出最大的几个
print(heapq.nlargest(3, nums)) # Prints [42, 37, 23]
# 找出最小的几个
print(heapq.nsmallest(3, nums)) # Prints [-4, 1, 2]
[42, 37, 23]
[-4, 1, 2]

使用nlargest可以找出最大的几个元素,相反的nsmalllest找最小的几个元素。如果需要找的是字典类型呢?还有第三个参数key,指定我们对数据进行的操作,key接受一个函数。

在下面的例子中,我们需要对字典按价格大小来排序查找。

portfolio = [
{'name': 'IBM', 'shares': 100, 'price': 91.1},
{'name': 'AAPL', 'shares': 50, 'price': 543.22},
{'name': 'FB', 'shares': 200, 'price': 21.09},
{'name': 'HPQ', 'shares': 35, 'price': 31.75},
{'name': 'YHOO', 'shares': 45, 'price': 16.35},
{'name': 'ACME', 'shares': 75, 'price': 115.65}
]
# key接受一个匿名函数,这个函数的作用是找出字典中price的值。
cheap = heapq.nsmallest(3, portfolio, key=lambda s: s['price'])
expensive = heapq.nlargest(3, portfolio, key=lambda s: s['price'])
print(cheap)
print(expensive)
[{'name': 'YHOO', 'shares': 45, 'price': 16.35}, {'name': 'FB', 'shares': 200, 'price': 21.09}, {'name': 'HPQ', 'shares': 35, 'price': 31.75}]
[{'name': 'AAPL', 'shares': 50, 'price': 543.22}, {'name': 'ACME', 'shares': 75, 'price': 115.65}, {'name': 'IBM', 'shares': 100, 'price': 91.1}]

如果你仅仅想查找唯一的最小或最大(N=1)的元素的话,那么使用 min() 和 max() 函数会更快些。

除了使用堆排序,python中还有sorted排序和list.sorted,这两个排序最终生成以列表表示的排序结果,堆排序也是。不过sorted在排序时会新建一个列表再进行排序,而list.sorted会直接对数据进行就地排序,而且要求输入的数据必须为列表。

具名元组

什么是具名元组?有时候我们需要用一个类来表示某个事物,但是并不想定义一个类然后咔哒咔哒写一大段类的表示,这个时候就可以使用具名元组,它可以用来快速生成类。比方说定义一个学生类,属性包括姓名,年龄,学号:

from collections import namedtuple
# 第一个参数是类的名字,第二个参数为类中的数据,可以为字符串,或者字符串组成的列表
Student = namedtuple("Student", ['name', 'age', 'id'])
Studen = namedtuple("Studen", "name age id")
s1 = Studen('zhuzhezhe', '23', '001')
s2 = Student('zhuzhezhe', '23', '001')
print(s1)
print(s2)
Studen(name='zhuzhezhe', age='23', id='001')
Student(name='zhuzhezhe', age='23', id='001')

具名元组放在collections模块下的nametuple中,第一个参数是类的名字,第二个参数为类中的数据,可以为字符串,或者字符串组成的列表。

以上就是一些不太常见的数据类型的介绍,当然不止这些,具体可以看看python官方手册。

下次我们来说说python中常见数据类型的一些不常见的用法,如果用到了效率会翻倍。