Shawn's Blog
目录 · 8 节

Python 奇技淫巧 (一) 列表、集合、字典

文章中的代码仅在Python3中测试成功,没有在Python2中测试。

0X00 *表达式

从某个可迭代对象中分解出N个元素,但是这个可迭代的对象可能会超过N,会出现too many values to unpack异常。

比如我这儿有N个统计信息,因为第一次和最后一次的信息不准确需要删除掉,而将中间的信息保留下来,那么就可以这么弄。

python
1#!/usr/bin/python
2# coding=utf-8
3
4if __name__ == '__main__':
5    grade = [23, 45, 42, 45, 78, 98, 89, 97, 69, 77, 88, 50, 65, 99, 98]
6    first, *new_grade, last = grade
7    print(new_grade)

这里的赋值就是将第一个和最后一个赋给了first和last,而中间的给了new_grade

0X01 定长队列

有一种情况:程序在运行的时候会记录日志,比如说web程序的访问历史。如果我们需要只保留最后的1W条数据,那么很快能想到使用一个列表,每次插入数据的时候判断长度,然后对应的append和del。但是有一个更简单且更快速的方法就是使用collections.deque()。下面的例子中有一个1024长的列表,我们列表里只存最新的7条。

python
1#!/usr/bin/python
2# coding=utf-8
3
4# 导入一个包
5import collections
6
7if __name__ == '__main__':
8	# 当做一种数据解雇来用就可以
9    auto_queue = collections.deque(maxlen=7)
10    my_list = range(1024)
11    for i in my_list:
12        auto_queue.append(i)
13    print(auto_queue)

运行之后可以看到,列表里只保存了最后插入的七条数据。

0X02 最大最小的几个元素

当我们有一个列表,需要找到列表里最大的N个元素时,一般会想到先排序然后分片,这想法当然不多,但是还有一个更好用的方法:

python
1#!/usr/bin/python
2# coding=utf-8
3
4import heapq
5
6
7if __name__ == '__main__':
8    my_list = [34, 234, 56, 56, 345, 456, 23, 213, 456, 8, 98, 43, 2, 67]
9    print('max: ', heapq.nlargest(3,  my_list))	# 找到最大的三个
10    print('min: ', heapq.nsmallest(2, my_list)) # 找到最小的两个

我这里用列表来演示,但是这个方法支持更复杂的数据结构。比如我有一个列表,列表里包含很多个字典,字典里是学生考试信息,那么我就可以用考试分数来找到前三名:

python
1#!/usr/bin/python
2# coding=utf-8
3
4import heapq
5
6
7if __name__ == '__main__':
8    my_list = [{'name': '小明', 'grade': 56}, {'name': '小红', 'grade': 87}, {'name': '小刚', 'grade': 67},
9               {'name': '小志', 'grade': 46}, {'name': '小逗逼', 'grade': 99}, {'name': '小华', 'grade': 85},]
10    print('max: ', heapq.nlargest(3,  my_list, key=lambda s: s['grade']))
11    print('min: ', heapq.nsmallest(3, my_list, key=lambda s: s['grade']))

key 后面的 lambda s: s['grade']是用了一个 匿名函数 。列表里唯一的值就是排序的关键字。更多关于更多关于匿名函数

如果N相对总数据量来说很小,可以用heapq.heapify()获得更好的性能。这个函数会将原来的集合转变成列表并以 的形式排序。而堆最重要的一个特性就是最小的那个元素一定在第一位。所以我们可以利用这个性质来获取最小的前N个。

python
1#!/usr/bin/python
2# coding=utf-8
3
4import heapq
5
6
7if __name__ == '__main__':
8    my_list = [234, 324, 456, 567, 345, 23, 546, 567, 98, 45, 2, 576]
9    heapq.heapify(my_list)
10    print(my_list)	# 查看排序结果
11    print(heapq.heappop(my_list))	# 取第一个元素,并重拍
12    print(heapq.heappop(my_list))
13    print(heapq.heappop(my_list))

0X03 优先级队列

普通队列都是按照FIFO(first in first out)来增删数据,有些特殊情况需要给每个元素设定优先级,push元素的时候设定优先级,pop的时候找到优先级最高的。比如说操作系统的任务调度就是这样的,会给每个进程设置优先级。不过当然,不会使用Python实现的了。这里的内部也是用堆来实现的,所以在15行的位置用了-priority来让堆反向排、

python
1#!/usr/bin/python
2# coding=utf-8
3
4import heapq
5
6
7# 这个类就是队列类
8class PriorityQueue:
9
10    def __init__(self):
11        self._queue = []    # 队列元素
12        self._index = 0     # 索引
13
14    def push(self, item, priority):
15        heapq.heappush(self._queue, (-priority, self._index, item))
16        self._index += 1
17
18    def pop(self):
19        return heapq.heappop(self._queue)[-1]
20
21
22# 队列中的数据类型
23class Item:
24
25    def __init__(self, name):
26        self.name = name    # 只有一个属性、name
27
28    def __repr__(self):
29        return 'Item({!r})'.format(self.name)   # 将格式化好的字符串返回
30
31if __name__ == '__main__':
32    my_queue = PriorityQueue()  # 实例化一个优先级队列
33    my_queue.push(Item('内核'), 99)   # 内核的优先级最高了
34    my_queue.push(Item('文件复制'), 40)
35    my_queue.push(Item('CS:GO'), 75)
36    print(my_queue.pop())   # 找到优先级最高的

0X04 一键多值

我们可以轻松的写出用一个键对应多个值的字典,只需要让键对应到列表或者集合就好了,但是要啰里啰嗦写一大堆东西。其实可以用一个内建的方法来解决这个问题。通过这个方法可以快速创建这种字典,也可以像操作普通列表一样操作里面的数据。

python
1#!/usr/bin/python
2# coding=utf-8
3
4from collections import defaultdict
5
6if __name__ == '__main__':
7    my_dic = defaultdict(list)
8    my_dic['name'].append('李华')
9    my_dic['qq'].append('66666')
10    my_dic['qq'].append('23333')
11    my_dic['qq'].append('88888')
12    print(my_dic)
13```python
14
15# 0X05 分片命名
16
17Python中分片非常好用,有的时候会在程序中出现很多分片,管理起来特别麻烦。可以通过这种方式给分片命名,下次再次调用的时候可以直接使用分片的名字。
18
19```python
20#!/usr/bin/python
21# coding=utf-8
22
23
24if __name__ == '__main__':
25    data = 'shawn 17 M'
26    name = slice(0, 5)
27    age  = slice(7, 8)
28    sex  = slice(9, 10)
29    print(data[name])
30    print(data[age])
31    print(data[sex])

0X06 词频统计

从一个序列中找到出现次数最多的元素。Counter对象还可以进行简单的加减,比如a序列里出现了10次’hello’而b序列里出现了3次’hello’,那么a+b的话’hello’的值就会变成13。

python
1#!/usr/bin/python
2# coding=utf-8
3
4from collections import Counter
5
6
7if __name__ == '__main__':
8    data = ['hello', 'world', 'hey', 'hello', 'world', 'jack', 'hey', 'york', 'hey', 'hello', 'hello']
9    word_count = Counter(data)
10    print(word_count.most_common(1))	# 这个参数1可以更改,表示的是出现次数最多的几个元素

0X07 对字典列表排序

比如我们从数据库中查询到了部分学生的成绩,每个学生的信息存成一个字典,多个字典组成一个列表。然后需要让列表按学生成绩排序。

python
1#!/usr/bin/python
2# coding=utf-8
3
4from operator import itemgetter
5
6
7if __name__ == '__main__':
8    student = [
9        {'name': '小明', 'mark': 98},
10        {'name': '小红', 'mark': 87},
11        {'name': '小刚', 'mark': 58},
12        {'name': '李华', 'mark': 100}
13    ]
14
15    student = sorted(student, key=itemgetter('name'))
16
17    for i in student:
18        print(i)

0X08 筛选序列

有一个列表,里面全是某次考试的成绩,需要成绩列表中找到所有的不及格成绩。可以轻松写出:定义空列表,for遍历成绩单,判断<60的就append。但是还有一个更方便的方案,就是使用 列表推导式 来完成。更多关于列表推导式

python
1#!/usr/bin/python
2# coding=utf-8
3
4
5if __name__ == '__main__':
6    my_list = [34, 56, 67, 78, 95, 23, 96, 23, 86, 78, 89, 45]
7    print([n for n in my_list if n <= 60])

也可以用同样的方式来从字典中筛选子字典。

python
1#!/usr/bin/python
2# coding=utf-8
3
4
5if __name__ == '__main__':
6    mark_list = {
7        '小明': 58,
8        '小红': 94,
9        '小刚': 67,
10        '小智': 76,
11        '小亮': 45
12    }
13
14    unpass = {key:value for key, value in mark_list.items() if value < 60}
15    print(unpass)
本文标题
Python 奇技淫巧 (一) 列表、集合、字典
文章作者
Shawn
版权声明
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。

如果这篇文章对你有帮助,可以请我喝杯咖啡 ☕

评论