目录

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

目录

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

0X00 *表达式

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

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

    #!/usr/bin/python
    # coding=utf-8

    if __name__ == '__main__':
        grade = [23, 45, 42, 45, 78, 98, 89, 97, 69, 77, 88, 50, 65, 99, 98]
        first, *new_grade, last = grade
        print(new_grade)

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

0X01 定长队列

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

    #!/usr/bin/python
    # coding=utf-8

    # 导入一个包
    import collections

    if __name__ == '__main__':
    	# 当做一种数据解雇来用就可以
        auto_queue = collections.deque(maxlen=7)
        my_list = range(1024)
        for i in my_list:
            auto_queue.append(i)
        print(auto_queue)

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

0X02 最大最小的几个元素

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

    #!/usr/bin/python
    # coding=utf-8

    import heapq


    if __name__ == '__main__':
        my_list = [34, 234, 56, 56, 345, 456, 23, 213, 456, 8, 98, 43, 2, 67]
        print('max: ', heapq.nlargest(3,  my_list))	# 找到最大的三个
        print('min: ', heapq.nsmallest(2, my_list)) # 找到最小的两个

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

    #!/usr/bin/python
    # coding=utf-8

    import heapq


    if __name__ == '__main__':
        my_list = [{'name': '小明', 'grade': 56}, {'name': '小红', 'grade': 87}, {'name': '小刚', 'grade': 67},
                   {'name': '小志', 'grade': 46}, {'name': '小逗逼', 'grade': 99}, {'name': '小华', 'grade': 85},]
        print('max: ', heapq.nlargest(3,  my_list, key=lambda s: s['grade']))
        print('min: ', heapq.nsmallest(3, my_list, key=lambda s: s['grade']))

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

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

    #!/usr/bin/python
    # coding=utf-8

    import heapq


    if __name__ == '__main__':
        my_list = [234, 324, 456, 567, 345, 23, 546, 567, 98, 45, 2, 576]
        heapq.heapify(my_list)
        print(my_list)	# 查看排序结果
        print(heapq.heappop(my_list))	# 取第一个元素,并重拍
        print(heapq.heappop(my_list))
        print(heapq.heappop(my_list))

0X03 优先级队列

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

    #!/usr/bin/python
    # coding=utf-8

    import heapq


    # 这个类就是队列类
    class PriorityQueue:

        def __init__(self):
            self._queue = []    # 队列元素
            self._index = 0     # 索引

        def push(self, item, priority):
            heapq.heappush(self._queue, (-priority, self._index, item))
            self._index += 1

        def pop(self):
            return heapq.heappop(self._queue)[-1]


    # 队列中的数据类型
    class Item:

        def __init__(self, name):
            self.name = name    # 只有一个属性、name

        def __repr__(self):
            return 'Item({!r})'.format(self.name)   # 将格式化好的字符串返回

    if __name__ == '__main__':
        my_queue = PriorityQueue()  # 实例化一个优先级队列
        my_queue.push(Item('内核'), 99)   # 内核的优先级最高了
        my_queue.push(Item('文件复制'), 40)
        my_queue.push(Item('CS:GO'), 75)
        print(my_queue.pop())   # 找到优先级最高的

0X04 一键多值

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

    #!/usr/bin/python
    # coding=utf-8

    from collections import defaultdict

    if __name__ == '__main__':
        my_dic = defaultdict(list)
        my_dic['name'].append('李华')
        my_dic['qq'].append('66666')
        my_dic['qq'].append('23333')
        my_dic['qq'].append('88888')
        print(my_dic)
```python

# 0X05 分片命名

Python中分片非常好用有的时候会在程序中出现很多分片管理起来特别麻烦可以通过这种方式给分片命名下次再次调用的时候可以直接使用分片的名字

```python
    #!/usr/bin/python
    # coding=utf-8


    if __name__ == '__main__':
        data = 'shawn 17 M'
        name = slice(0, 5)
        age  = slice(7, 8)
        sex  = slice(9, 10)
        print(data[name])
        print(data[age])
        print(data[sex])

0X06 词频统计

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

    #!/usr/bin/python
    # coding=utf-8

    from collections import Counter


    if __name__ == '__main__':
        data = ['hello', 'world', 'hey', 'hello', 'world', 'jack', 'hey', 'york', 'hey', 'hello', 'hello']
        word_count = Counter(data)
        print(word_count.most_common(1))	# 这个参数1可以更改,表示的是出现次数最多的几个元素

0X07 对字典列表排序

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

    #!/usr/bin/python
    # coding=utf-8

    from operator import itemgetter


    if __name__ == '__main__':
        student = [
            {'name': '小明', 'mark': 98},
            {'name': '小红', 'mark': 87},
            {'name': '小刚', 'mark': 58},
            {'name': '李华', 'mark': 100}
        ]

        student = sorted(student, key=itemgetter('name'))

        for i in student:
            print(i)

0X08 筛选序列

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

    #!/usr/bin/python
    # coding=utf-8


    if __name__ == '__main__':
        my_list = [34, 56, 67, 78, 95, 23, 96, 23, 86, 78, 89, 45]
        print([n for n in my_list if n <= 60])

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

    #!/usr/bin/python
    # coding=utf-8


    if __name__ == '__main__':
        mark_list = {
            '小明': 58,
            '小红': 94,
            '小刚': 67,
            '小智': 76,
            '小亮': 45
        }

        unpass = {key:value for key, value in mark_list.items() if value < 60}
        print(unpass)
☕ 如果喜欢这篇文章,欢迎打赏 5 毛钱
支付宝
支付宝二维码
USDT
USDT二维码
微信
微信二维码