Python3 CookBook | 数据结构和算法(一)

文章首发于知乎专栏,欢迎关注。
zhuanlan.zhihu.com/pythoncookb…python

如下测试代码所有基于 Python3。bash

Python 提供了大量的内置数据结构,包括列表,集合以及字典。在工做和编码中,能够说每天和它们打交道,常常碰到查询,排序和过滤等等这些问题,虽然每次解决这些问题并不困难,但总感受代码写的很麻烦,不够优雅。微信

最近经过阅读《Python3 CookBook》,了解了一些更优秀的方法,作一些简单记录,与你们分享。数据结构

一、解压可迭代对象赋值给多个变量

咱们都知道,一个序列是能够赋值给多个变量的,就像下面这样:app

In [7]: p = (1, 2, 3)

In [8]: x, y, z = p

In [9]: x
Out[9]: 1复制代码

但若是接收的变量个数和序列元素个数不一致,就会报错,若是你不知道元素个数的话,能够采用下面这样的方式:函数

In [10]: x, *y = p

In [11]: y
Out[11]: [2, 3]复制代码

经过这种星号的方式,就能够解压不肯定个数或任意个数的可迭代对象了,是否是很棒呢?测试

那么,用这个方法能够解决哪些问题呢?优化

先来看一种状况,如今有一个序列,去掉第一个数和最后一个数,而后求剩下数的平均值。ui

这个问题很简单,个人第一反应是循环求和,而后计算平均值,显然很麻烦。这时候星号表达式就派上用场了:编码

def drop_first_last(items):
  first, *middle, last = items
  return avg(middle)复制代码

再看一种状况,好比字符串的分割:

In [12]: line = 'drwxr-xr-x 41 zyx staff 1.4K 11 24 08:53 zyx'

In [13]: info, *fields, homedir = line.split(' ')

In [14]: info
Out[14]: 'drwxr-xr-x'

In [15]: homedir
Out[15]: 'zyx'复制代码

二、保留最后 N 个元素

这个问题也是常常会遇到的,好比只取文件中知足要求的前五行,或者只返回知足要求的最新十条数据。个人第一反应是列表,而后经过 push 和 pop 来操做列表来实现。

其实经过 collections.deque 能够很容易解决这个问题,使用 deque(maxlen=N) 构造函数新建一个固定大小的队列。当新元素加入而且这个队列已满时,最早进入队列的元素便会被移除,符合先进先出的原则。

In [16]: from collections import deque

In [17]: q = deque(maxlen=3)

In [18]: q.append(1)

In [19]: q.append(2)

In [20]: q.append(3)

In [21]: q
Out[21]: deque([1, 2, 3])

In [22]: q.append(4)

In [23]: q
Out[23]: deque([2, 3, 4])复制代码

若是没有设置 maxlen 则是一个无限大小的队列,能够经过 appendleft 和 pop 在队首和队尾添加删除元素。

三、字典中的键映射多个值

如今有一个需求,构建一个字典,key 是用户 ID,value 为一个列表,列表元素能够是名字,电话等等,大概是这样:

d = {'id': ['name', 'phone']}复制代码

若是咱们本身构建这个字典,可能会像下面这样来实现:

d = {}
for key, value in items:
  if key not in d:
    d[key] = value
  d[key].append(value)复制代码

很麻烦,若是使用 collections 的 defaultdict 就很简单了。defaultdict 的一个特征就是它会自动初始化每一个 key 刚开始对应的值,因此咱们只关注添加元素操做就能够了。

优化后代码就变成了这样:

d = defaultdict(list)
for key, value in items:
  d[key].append(value)复制代码

四、字典排序

字典是无序的,但若是要控制字典中元素的顺序呢?可使用 colletions 中的 OrderedDict,以下:

d = OrderedDict()
d['foo'] = 1
d['bar'] = 2
d['spam'] = 3
d['grok'] = 4
# Outputs "foo 1", "bar 2", "spam 3", "grok 4"

for key in d:
  print(key, d[key])复制代码

OrderedDict 内部维护这一个根据键插入顺序排序的双向链表。每次新元素插入时,便会被放在链表尾部,对于已经存在的键,并不会改变键的顺序。

但须要注意的是,OrderedDict 的大小是普通字典的两倍,因此在构建一个须要大量 OrderedDict 实例的数据结构时,就要考虑大量内存消耗的影响了。

五、字典的运算

如何取出字典中的最小值,或者对字典进行排序呢?

首先咱们来看看直接使用普通的数学运算函数

In [25]: d = {'a': 11, 'b': 43, 'c': 3, 'd': 65}

In [26]: min(d)
Out[26]: 'a'复制代码

它比较的逻辑是直接比较 key,而后取出对应的 key,但若是要比较 value 呢?

In [28]: min(d.values())
Out[28]: 3复制代码

结果是正确的,但彷佛并不完美,若是键值一块儿返回就完美了。这时候就该 zip 登场了,它的做用是可使键和值反转过来。

In [29]: min(zip(d.values(), d.keys()))
Out[29]: (3, 'c')复制代码

它直接返回了值最小的键和值,这样就很好了,无论须要哪一个信息均可以直接使用。若是要对这个字典排序的话也很简单:

In [34]: sorted(zip(d.values(), d.keys()))
Out[34]: [(3, 'c'), (11, 'a'), (43, 'b'), (65, 'd')]复制代码

先写这么多吧,未完待续。。。

欢迎留言,或者添加我我的微信 zhangyx6a 交流沟通,不是微商。

相关文章
相关标签/搜索