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开始常规字典也能记住插入的顺序。

有序字典和常规字典仍然有一些不同之处:

  1. 常规字典被设计用于映射操作,保持插入顺序是其次的。
  2. 有序字典被设计用于排序操作,高效空间使用,迭代速度和更新操作是其次的
  3. 在算法上,有序字典处理频繁排序操作比常规字典更好,这个特性让有序字典可以适合追踪最近访问,如LRU
  4. OrderedDict 类的 popitem() 方法有不同的签名。它接受一个可选参数来指定弹出哪个元素
  5. 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的更多相关文章

  1. python常用内建模块 collections,bs64,struct,hashlib,itertools,contextlib,xml

    #  2  collections 是Python内建的一个集合模块,提供了许多有用的集合类. # 2.1 namedtuple #tuple可以表示不变集合,例如,一个点的二维坐标就可以表示成: p ...

  2. python原生的日志模块

    Python中有个logging模块可以完成相关信息的记录,在debug时用它往往事半功倍 1. 日志级别 日志一共分成5个等级,从低到高分别是: DEBUG INFO WARNING ERROR C ...

  3. Python其他数据结构collection模块-namtuple defaultdict deque Queue Counter OrderDict arrary

    nametuple 是tuple扩展子类,命名元组,其实本质上简单类对象 from collections import namedtuple info = namedtuple("Info ...

  4. python常用内建模块--collections

    1.namedtuple #namedtuple是一个函数,它用来创建一个自定义的tuple对象,并且规定了tuple元素的个数,并可以用属性而不是索引来引用tuple的某个元素.#这样一来,我们用n ...

  5. python模块--collections

    python的内建模块collections有几个关键的数据结构,平常在使用的时候,开发者可以直接调用,不需要自己重复制造轮子,这样可以提高开发效率. 1. deque双端队列 平常我们使用的pyth ...

  6. day13 函数模块之序列化 random 模块 os模块 sys模块 hashlib模块 collections模块

    json import json dic = {'k1':'v1','k2':'v2','k3':'v3'} str_dic = json.dumps(dic) #序列化:将一个字典转换成一个字符串 ...

  7. Python常用数据结构之collections模块

    Python数据结构常用模块:collections.heapq.operator.itertools collections collections是日常工作中的重点.高频模块,常用类型由: 计数器 ...

  8. 不可不知的Python模块: collections

    原文:http://www.zlovezl.cn/articles/collections-in-python/ Python作为一个“内置电池”的编程语言,标准库里面拥有非常多好用的模块.比如今天想 ...

  9. Python常用数据结构之heapq模块

    Python数据结构常用模块:collections.heapq.operator.itertools heapq 堆是一种特殊的树形结构,通常我们所说的堆的数据结构指的是完全二叉树,并且根节点的值小 ...

随机推荐

  1. list通过比较器进行排序

    Collections.sort(dataList,new Comparator<BaseTransitData>(){            public int compare(Bas ...

  2. Java Timestamp 类的使用

    很简单,我们可以这样声明 Timestamp ts=new Timestamp(new Date().getTime());这样我们就可以得到时间比较具体的一个类型转换!!! 在开发web应用中,针对 ...

  3. 【Java 基础】 instanceof和isInstance区别详解

    obj instanceof class 也就是说这个对象是不是这种类型, 1.一个对象是本身类的一个对象 2.一个对象是本身类父类(父类的父类)和接口(接口的接口)的一个对象 3.所有对象都是Obj ...

  4. thinkPHP的多语言支持如何配置和部署

    框架底层语言包位于:ThinkPHP/Lang/zh-cn.php 可以参考如何编写语言文件 第一步:项目目录下的配置文件中配置多语言支持的相关选项 以我的路径为例是Application\Commo ...

  5. OpenGL ES2.0 入门经典例子

    原文链接地址:http://www.raywenderlich.com/3664/opengl-es-2-0-for-iphone-tutorial 免责申明(必读!):本博客提供的所有教程的翻译原稿 ...

  6. net start Mysql 启动服务时 ,显示"Mysql服务正在启动 Mysql服务无法启动 服务没有报告任何错误

    一.问题 有时候,输入net start Mysql 启动服务时 mysql>net start Mysql 显示 Mysql服务正在启动 Mysql服务无法启动 服务没有报告任何错误 二.原因 ...

  7. threejs 贴图动画总结

    引言 在三维可视化中,会涉及到很多动画,其中贴图动画是其中很重要的一种,本文介绍几种贴图动画的思路,供大家一起探讨. 流动动画 流动动画通过设置贴图的repeat属性,并不断改变贴图对象的offset ...

  8. UMDCTF 2021

    6道pwn题,4道可以做.剩下一道题是arm架构,一道题是内核,溜了溜了. Jump_Not_Easy 1 from pwn import * 2 3 p = process('./pwn') 4 e ...

  9. odoo views中html的奇怪问题

    在我创建了字段类型为 fields.Html 以后,确出现了两种不同的情况 下图中,content是此类型的,可以正常显示不需要加widget(小部件)="html" <fo ...

  10. SPQuery ViewAttributes Sharepoint列表查询范围

    SPSite site=new SPSite(SPContext.Current.Web.Url); SPWeb web=site.OpenWeb(); SPList splist=web.Lists ...