Python原生数据结构增强模块collections
collections简介
python提供了4种基本的数据结构:list、tuple、dict、set。基本数据结构完全可以hold住所有的场景,但是在处理数据结构复杂的场景时,这4种数据结构有时会显的单一,比如将相同字母组成的字符串归类到列表中,是一个key为字符串,value为列表的数据结构,复杂度为O(1)的情况下完成LRU(力扣原题)。
这个时候今天的主角collections
包就可以登场了。collections是基本数据结构的高性能优化版,它提供了多个有用的集合类,熟练掌握这些集合类,不仅可以让我们让写出的代码更加Pythonic,也可以提高我们程序的运行效率。
Counter
简单使用
Counter是一个简单的计数器,例如,统计字符出现的个数,并且会根据出现次数从大到小排列好:
>>> from collections import Counter
>>> Counter("hello world")
Counter({'l': 3, 'o': 2, ' ': 1, 'e': 1, 'd': 1, 'h': 1, 'r': 1, 'w': 1})
>>>
功能:
Counter是一个计数器工具,提供快速和方便的计数。从类型上划分,Counter是一个dict的子类,元素像字典一样存储,key是统计的元素,value是统计的个数。
Counter可统计多种数据类型,包括:字符串,列表,字典,元组,集合等。
字符串
>>> str = "hello world"
>>>
>>> res = Counter(str)
>>> res
Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1})
列表
>>> arr = [1,2,3,4,2,3,4,5]
>>> res = Counter(arr)
>>> res
Counter({2: 2, 3: 2, 4: 2, 1: 1, 5: 1})
字典
>>> map = {"a":3, "b":2, "c":1}
>>> res = Counter(map)
>>> res
Counter({'a': 3, 'b': 2, 'c': 1})
元组
>>> tu = (1,2,3,2,3,4,2,3,5)
>>> res = Counter(tu)
>>> res
Counter({2: 3, 3: 3, 1: 1, 4: 1, 5: 1})
集合
>>> Set = {1,2,3,3,4,5,4,5,6}
>>> Set
{1, 2, 3, 4, 5, 6}
>>> res = Counter(Set)
>>> res
Counter({1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 6: 1})
Counter拥有的方法
1.elements()
返回一个迭代器,其中每个元素将重复出现计数值所指定次。元素返回的顺序是按照元素在原本序列中首次出现的顺序
>>> str = "hello world"
>>> res = Counter(str)
>>> res
Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1})
>>> list(res.elements())
['h', 'e', 'l', 'l', 'l', 'o', 'o', ' ', 'w', 'r', 'd']
>>> c = Counter(a=4, b=2, c=0, d=-2)
>>> list(c.elements())
['a', 'a', 'a', 'a', 'b', 'b']
2.most_common()
返回一个列表,其中包含n个出现次数最高的元素及出现次数,按常见程度由高到低排序。 如果 n 被省略或为None, 将返回计数器中的所有元素。
计数值相等的元素按首次出现的顺序排序,经常用来计算top词频的词语。
>>> str = "hello world"
>>> res = Counter(str)
>>> res
Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1})
>>> res.most_common(2)
[('l', 3), ('o', 2)]
3.subtract()
将两个Counter相减,a.sbutract(b),a中计数减少相应的个数
>>> from collections import Counter
>>> a = Counter("hello world")
>>> a
Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1})
>>> b = Counter("hello")
>>> a.subtract(b)
>>> a
Counter({'l': 1, 'o': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1, 'h': 0, 'e': 0})
4.字典方法
通常字典方法都可用于Counter对象,除了有两个方法工作方式与字典并不相同。
a. fromkeys(iterable)
这个类方法没有在Counter中实现。
b. update([iterable-or-mapping])
Counter对象更新另一个对象。但是不同之处在于字典的update是更新元素的value,而Counter的update是将元素的统计相加。
defaultdict
defaultdict是带默认值的字典,属于内置字典的子集,它重写了一个方法和添加一个可写实例变量。普通字典在取出一个不存在的key时,会抛出KeyError错误。如果希望在key不存在时返回一个默认值,可以使用字典的get方法,如map.get(key, None),或者是使用defaultdict。defaultdict作用就是在字典查找不存在的key时返回一个默认值而不是KeyError。
功能:
为添加到字典中的每一个key增加一个默认值,当查询一个不存在的元素时,会返回该默认类型和添加一个可写实例变量。剩下的方法都和常规字典一样。
默认值为列表
>>> dict_demo = defaultdict(list)
>>> arr = [("yello", 1),("blue", 2), ("green",3), ("yello", 9)]
>>> for key, value in arr:
... dict_demo[key].append(value)
...
>>> dict_demo
defaultdict(<class 'list'>, {'yello': [1, 9], 'blue': [2], 'green': [3]})
默认值为数字
>>> from collections import defaultdict
>>> dict_demo = defaultdict(int)
>>> count = [("a",1),("b",2),("c",3),("a",4)]
>>>
>>> for key, value in count:
... dict_demo[key] += value
...
>>> dict_demo
defaultdict(<class 'int'>, {'a': 5, 'b': 2, 'c': 3})
默认值的类型
dict_demo = defaultdict(str) 默认值:空字符串
dict_demo = defaultdict(int) 默认值:0
dict_demo = defaultdict(list) 默认值:空列表
dict_demo = defaultdict(dict) 默认值:空字典
dict_demo = defaultdict(tuple) 默认值:空元素
dict_demo = defaultdict(set) 默认值:空集合
当访问不存在的key时,会返回默认值,同时在字典中创建该记录。
deque
在数据结构中,队列和堆栈是两个非常重要的数据类型,一个先进先出,一个后进先出。在python中,使用list存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为list是线性存储,数据量大的时候,插入和删除效率很低。
deque是为了高效实现插入和删除操作的双向链表结构,非常适合实现队列和堆栈这样的数据结构
功能:
deque是一个栈和队列的综合,发音为deck,可以成为双向队列。deque支持线程安全,两端都支持高效的入栈和出栈操作,时间复杂度为O(1)。
虽然list支持类似的操作,但它们针对快速的固定长度操作进行了优化,并为pop(0) 和insert(0,v)操作带来了O(n)内存移动成本,这两种操作都会更改基础数据表示的大小和位置。
如果未指定maxlen或为None,则deque可能会增长到任意长度。否则,deque将绑定到指定的最大长度。一旦有界长度deque已满,添加新项时,从另一端丢弃相应数量的项。
>>> from collections import deque
>>>
>>>
>>> my_deque = deque([1,2,3])
>>>
>>> my_deque.append(4)
>>>
>>> my_deque
deque([1, 2, 3, 4])
>>> my_deque.appendleft(0)
>>>
>>>
>>> my_deque
deque([0, 1, 2, 3, 4])
>>> my_deque.pop()
4
>>>
>>> my_deque.popleft()
0
>>>
>>> my_deque
deque([1, 2, 3])
deque拥有的方法
deque拥有众多的方法,因为deque
是一个双向链表,所以在头和尾都可以操作,方法有如下:
deque.append(x)
在队列右边(尾部)插入x
deque.appendleft(x)
在队列左边(头部)插入x
deque.pop()
在队列左边(尾部)出栈
deque.popleft()
在队列右边(头部)出栈
deque.clear()
清空队列,初始化队列长度为1
deque.copy()
创建一个浅拷贝的队列
deque.count(x)
计算队列中x元素的个数
deque.extend(iterable)
将可迭代对象扩展到队列右边
deque.extendleft(iterable)
将可迭代对象扩展到队列左边
deque.index(x)
返回元素x在队列中的位置,没有找到抛出异常ValueError
deque.insert(i, x)
插入元素x到指定位置x。如果位置超出范围,抛出IndexError异常
deque.remove(x)
删除第一个找到的元素x,没有元素抛出ValueError异常
deque.reverse()
逆序
deque.rotate(n)
将队列向右移动n个元素,如果n为负数则向左移动n个元素
deque.maxlen()
返回队列长度,为空返回None。
namedtuple
命名元组类似于一个对象,包含只读属性的变量
功能:
命名元组为元组中的每个位置分配意义,并允许更可读、自文档化的代码。它们可以在任何使用常规元组的地方使用,并且它们增加了通过名称而不是位置索引访问字段的能力。
namedtuple创建一个和tuple类似的对象,而且对象可以通过名字访问。这对象更像带有数据属性的类,不过数据属性是只读的。
namedtuple(typename,field_names,*,verbose=False, rename=False, module=None)
1)typename:该参数指定所创建的命名元组的名字
2) field_names:该参数指定各个元素对应的名字,如 ['x','y'],也可以用"x,y"
简单使用
有一个长方体,长宽高的属性用一个元组来表示(12, 15, 16)。虽然三个数值能够表示一个长方体,但是这个元组并没有清楚的指明三个字段分别代表什么。其实三个字段分别是:
长 | 宽 | 高 |
---|---|---|
12 | 15 | 16 |
使用namedtuple来表示就能够很清晰的表示出来。
from collections import namedtuple
Cuboid = namedtuple("Cuboid", ["length", "width", "height"])
one = Cuboid(12, 15, 16)
>>> one[0]
12
>>> one.length
12
>>>
>>>
>>> one[1]
15
>>> one.width
15
>>>
>>>
>>> one[2]
16
>>> one.height
16
>>>
可以看出namedtuple的方法方式有如下关系:
noe.length
== one[0]
one.width
== one[1]
one.height
== one[2]
三个方法
除了继承元组的方法,命名元组还支持三个额外的方法和两个属性
1._asdict()
返回一个新的 dict ,它将字段名称映射到它们对应的值
>>> one._asdict()
OrderedDict([('length', 12), ('width', 15), ('height', 16)])
2._replace
>>> two = one._replace(length=33)
>>> two.length
33
3._make
类方法,从存在的序列或迭代实例创建一个新实例。
>>> arr = [100,200,150]
>>>
KeyboardInterrupt
>>> three = Cuboid._make(arr)
>>> three
Cuboid(length=100, width=200, height=150)
>>> three[0]
100
>>> three.length
100
两个属性
1._fields
出了字段名
>>> one._fields
('length', 'width', 'height')
2.defaults
给字段设置默认值
>>> Cuboid = namedtuple("Cuboid", ["length", "width", "height"], defaults=[22,33,44])
>>> four = Cuboid()
>>> four[0]
22
>>> four.length
22
>>>
>>>
>>> four[1]
33
>>> four.width
33
OrderedDict
有顺序的字典和常规字典类似,但是有很多和排序有关的能力。但是有序字典现在变得不是那么重要了,因为在python3.7开始常规字典也能记住插入的顺序。
有序字典和常规字典仍然有一些不同之处:
- 常规字典被设计用于映射操作,保持插入顺序是其次的。
- 有序字典被设计用于排序操作,高效空间使用,迭代速度和更新操作是其次的
- 在算法上,有序字典处理频繁排序操作比常规字典更好,这个特性让有序字典可以适合追踪最近访问,如LRU
- OrderedDict 类的
popitem()
方法有不同的签名。它接受一个可选参数来指定弹出哪个元素 - OrderedDict 类有一个
move_to_end()
方法,可以有效地将元素移动到任一端
传统字典方法 | OrderedDict方法 | 差异 |
---|---|---|
clear | clear | |
copy | copy | |
fromkeys | fromkeys | |
get | get | |
items | items | |
keys | keys | |
pop | pop | |
popitem | popitem | OrderedDict 类的 popitem() 方法有不同的签名。它接受一个可选参数来指定弹出哪个元素。 |
setdefault | setdefault | |
update | update | |
values | values | |
move_to_end | 可以有效地将元素移动到任一端。 |
Python3.6之前的dict是无序的,但是在某些情形我们需要保持dict的有序性,这个时候可以使用OrderedDict.
>>> from collections import OrderedDict
>>>
>>> ordict = OrderedDict()
>>>
>>> ordict['x'] = 200
>>> ordict['y'] = 300
>>> ordict['z'] = 100
>>> ordict['a'] = 400
>>>
>>>
>>> ordict
OrderedDict([('x', 200), ('y', 300), ('z', 100), ('a', 400)])
>>> ordict.pop('z')
100
>>> ordict
OrderedDict([('x', 200), ('y', 300), ('a', 400)])
两个特殊方法
1.popitem
删除头或尾
dic.popitem(): 删除尾元素
dic.popitem(False): 删除头元素
>>> ordict.popitem()
('a', 400)
>>> ordict.popitem(False)
('x', 200)
2.dic.move_to_end()
: 将指定键值对移动到尾部
>>> ordict
OrderedDict([('y', 300), ('z', 100), ('a', 1), ('b', 2)])
>>> ordict.move_to_end('y')
>>> ordict
OrderedDict([('z', 100), ('a', 1), ('b', 2), ('y', 300)])
ChainMap
ChainMap 映射链
功能:
ChainMap提供了一种多个字典整合的方式,它没有去合并这些字典,而是将这些字典放在一个列表(maps)里,内部实现了很多 dict 的方法,大部分 dict 的方法,ChainMap 都能使用。
from collections import ChainMap
a = {'x':1,'y':2}
b = {'x':100, 'z':200}
c = ChainMap(a,b)
>>> c
ChainMap({'x': 1, 'y': 2}, {'x': 100, 'z': 200})
>>> c.get('x')
1
>>> c.get('z')
200
>>>
在存储中类似于[a,b],即[{'x': 1, 'y': 2}, {'x': 100, 'z': 200}],这是ChainMap的特点,按照前后顺序存储每一个map
操作
1.读取
对ChainMap的读取会从第一个map开始读,直到遇到指定的key,返回第一个遇到的元素
2.更新
对ChainMap的修改只会影响第一个元素
>>> c["x"] = 33
>>>
>>> c
ChainMap({'x': 33, 'y': 2}, {'x': 100, 'z': 200})
拥有的方法
1.maps
一个可以更新的映射列表。这个列表是按照第一次搜索到最后一次搜索的顺序组织的。它是仅有的存储状态,可以被修改。列表最少包含一个映射。
ChainMap内部存储了一个名为maps的list用以维护mapping关系, 这个list可以直接查看和修改,修改之后相应ChainMap值也就修改了.
>>> c.maps
[{'x': 1, 'y': 2}, {'x': 100, 'z': 200}]
2.new_child
new_child(m=None, **kwargs)
返回一个新的 ChainMap,其中包含一个新的映射,后面跟随当前实例中的所有映射。 如果指定了 m,它会成为新的映射加在映射列表的前面;如果未指定,则会使用一个空字典,因此调用 d.new_child() 就等价于 ChainMap({}, *d.maps)。 如果指定了任何关键字参数,它们会更新所传入的映射或新的空字典。 此方法被用于创建子上下文,它可在不改变任何上级映射的情况下被更新。
>>> c.new_child()
ChainMap({}, {'x': 33, 'y': 2}, {'x': 100, 'z': 200})
3.parents
属性返回一个新的 ChainMap 包含所有的当前实例的映射,除了第一个。这样可以在搜索的时候跳过第一个映射。 使用的场景类似在 nested scopes 嵌套作用域中使用 nonlocal 关键词。用例也可以类比内建函数 super() 。
一个 d.parents 的引用等价于 ChainMap(*d.maps[1:]) 。
>>> c.parents
ChainMap({'x': 100, 'z': 200})
>>>
ChainMap只是对之前的字典做一个引用,因此,修改ChainMap会影响到之前的字典,同理修改原来的字典也会影响到ChainMap
c["x"] = 33
>>> c.new_child()
ChainMap({}, {'x': 33, 'y': 2}, {'x': 100, 'z': 200})
>>> a
{'x': 33, 'y': 2}
>>>
>>> a['x'] = 44
>>> c
ChainMap({'x': 44, 'y': 2}, {'x': 100, 'z': 200})
总结
collections号称是基本数据结构的增强版,如果基本数据结构是iphone13,那collections就是iphone13 pro,iphone13 pro max。可以将是否熟练使用collections作为python进阶编程的一个衡量标准。
Python原生数据结构增强模块collections的更多相关文章
- python常用内建模块 collections,bs64,struct,hashlib,itertools,contextlib,xml
# 2 collections 是Python内建的一个集合模块,提供了许多有用的集合类. # 2.1 namedtuple #tuple可以表示不变集合,例如,一个点的二维坐标就可以表示成: p ...
- python原生的日志模块
Python中有个logging模块可以完成相关信息的记录,在debug时用它往往事半功倍 1. 日志级别 日志一共分成5个等级,从低到高分别是: DEBUG INFO WARNING ERROR C ...
- Python其他数据结构collection模块-namtuple defaultdict deque Queue Counter OrderDict arrary
nametuple 是tuple扩展子类,命名元组,其实本质上简单类对象 from collections import namedtuple info = namedtuple("Info ...
- python常用内建模块--collections
1.namedtuple #namedtuple是一个函数,它用来创建一个自定义的tuple对象,并且规定了tuple元素的个数,并可以用属性而不是索引来引用tuple的某个元素.#这样一来,我们用n ...
- python模块--collections
python的内建模块collections有几个关键的数据结构,平常在使用的时候,开发者可以直接调用,不需要自己重复制造轮子,这样可以提高开发效率. 1. deque双端队列 平常我们使用的pyth ...
- day13 函数模块之序列化 random 模块 os模块 sys模块 hashlib模块 collections模块
json import json dic = {'k1':'v1','k2':'v2','k3':'v3'} str_dic = json.dumps(dic) #序列化:将一个字典转换成一个字符串 ...
- Python常用数据结构之collections模块
Python数据结构常用模块:collections.heapq.operator.itertools collections collections是日常工作中的重点.高频模块,常用类型由: 计数器 ...
- 不可不知的Python模块: collections
原文:http://www.zlovezl.cn/articles/collections-in-python/ Python作为一个“内置电池”的编程语言,标准库里面拥有非常多好用的模块.比如今天想 ...
- Python常用数据结构之heapq模块
Python数据结构常用模块:collections.heapq.operator.itertools heapq 堆是一种特殊的树形结构,通常我们所说的堆的数据结构指的是完全二叉树,并且根节点的值小 ...
随机推荐
- Give You My Best Wishes
亲耐滴IT童鞋们: 感谢大家一直以来的支持,因为有你们的支持,才有我这么"拼"的动力!!爱你们哟 OC的学习已经告一段落,希望大家通过阅读这几篇浅薄的随笔,能够寻找到解决问题的方法 ...
- entfrm-boot开发平台功能介绍【entfrm开源模块化无代码开发平台】
简介 entfrm开发平台,是一个以模块化为核心的无代码开发平台,是一个集PC和APP快速开发.系统管理.运维监控.开发工具.OAuth2授权.可视化数据源管理与数据构建.API动态生成与统计.工作流 ...
- 莫烦python教程学习笔记——利用交叉验证计算模型得分、选择模型参数
# View more python learning tutorial on my Youtube and Youku channel!!! # Youtube video tutorial: ht ...
- C# 使用管理员权限运行程序
最近在开发OPCServer组件过程中,在注册opcServer是总是返回false,后来查找原因得知在本地主机注册opcServer时,需要使用管理员权限. OPCServer在一台机器上部署时只需 ...
- 关于Mysql java.sql.SQLException: Access denied for user 'root'@'localhost' (using password: YES)的问题
问题所在: 1.连接数据库一个是密码是否正确, 2.driver是否对, 3.有么有jar包冲突,
- 07- Vue3 UI Framework - Switch 组件
为了更好的提升用户体验,我们这里再做一个很常用的开关组件 switch 返回阅读列表点击 这里 需求分析 开始之前我们先做一个简单的需求分析 switch 组件应分为选中/未被选中,两种状态 可以通过 ...
- Wireshark(二):应用Wireshark观察基本网络协议
原文出处: EMC中文支持论坛 TCP: TCP/IP通过三次握手建立一个连接.这一过程中的三种报文是:SYN,SYN/ACK,ACK. 第一步是找到PC发送到网络服务器的第一个SYN报文,这标识了T ...
- CF313A Ilya and Bank Account 题解
Update \(\texttt{2021.3.6}\) 经求学的企鹅提醒修改了 Content 部分的数据范围. Content 有一个人的银行账户里有 \(n\) 元钱,他可以删去倒数第二位获最后 ...
- wordpress的.htaccess很容易就被挂马啊
wordpress的.htaccess很容易就被挂马啊 修改成这样吧: # BEGIN WordPress<IfModule mod_rewrite.c>RewriteEngine OnR ...
- 移动端适配文件(引入scss)
把此下代码放入scss文件 使用时候引入scss文件 @charset "UTF-8"; $yh:"Microsoft yahei"; @function rm ...