一、collections模块简介
除内置数据类型(dict、list、set、tuple)的基础上,collections模块还提供了几个额外的数据类型:Counter、deque、defaultdict、namedtuple和OrderedDict等。
(1)namedtuple: 生成可以使用名字来访问元素内容的tuple
(2)deque: 双端队列,可以快速的从另外一侧追加和推出对象
(3)Counter: 计数器,主要用来计数
(4)OrderedDict: 有序字典
(5)defaultdict: 带有默认值的字典
1. namedtuple的用法
我们知道tuple可以表示不变集合,例如,一个点的三维坐标就可以表示成:
p = (1, 2, 5)
print(p)
但是,看到(1, 2,5),很难看出这个tuple是用来表示一个三维坐标的。
此时,namedtuple就派上了用场:
from collections import namedtuple
# namedtuple('名称', [属性list]):
Point = namedtuple('Point', ['x', 'y', 'z'])
p = Point(1, 2, 5)
print(p)
print(p.x, p.y, p.z)
2. deque的用法
使用list存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为list是线性存储,数据量大的时候,插入和删除效率很低。
deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈:
from collections import deque
q = deque(['Lawrence', '小梁', '小黑', '小白'])
q.append('小黄') # 默认添加在右侧尾部
print(q)
q.appendleft('Python3')
print(q)
deque除了实现list的append()和pop()外,还支持appendleft()和popleft(),这样就可以非常高效地往头部添加或删除元素。
q.pop() # 从尾部删除
q.popleft() # 从头部删除,不能传值
print(q)
3. OrderedDict的用法
使用dict时,Key是无序的。在对dict做迭代时,我们无法确定Key的顺序。
如果要保持Key的顺序,可以用OrderedDict:
from collections import OrderedDict
d = dict([('name', 'Lawrence'), ('age', 18), ('sex', '男'), ('id', '1141400030')])
print(d) # dict的Key是无序的
{'name': 'Lawrence', 'age': 18, 'sex': '男', 'id': '1141400030'}
od = OrderedDict([('name', 'Lawrence'), ('age', 18), ('sex', '男'), ('id', '1141400030')])
print(od) # OrderedDict的Key是有序的
# OrderedDict([('name', 'Lawrence'), ('age', 18), ('sex', '男'), ('id', '1141400030')])
print(od['age']) # 获取key对应的值内容
注意:OrderedDict的Key会按照插入的顺序排列,不是Key本身排序
from collections import OrderedDict
od = OrderedDict()
od['name'] = 'Lawrence'
od['age'] = 18
od['work'] = '清洁工'
od['id'] = 1141440030
print(od.keys()) # 按照插入的Key的顺序返回
# 结果:odict_keys(['name', 'age', 'work', 'id'])
4. defaultdict的用法
有如下值集合 [16, 26, 46, 36, 66, 56, 76, 86, 96, 6…],将所有大于 66 的值保存至字典的第一个key中,将小于 66 的值保存至第二个key的值中。
即: {‘k1’: 大于66 , ‘k2’: 小于66}
方式一:原生字典解决方法
values = [16, 26, 46, 36, 66, 56, 76, 86, 96, 6]
my_dict = {'k1': [], 'k2': []}
for value in values:
if value > 66:
if value in my_dict['k1']:
break
else:
my_dict['k1'].append(value)
else:
if value in my_dict['k2']:
break
else:
my_dict['k2'].append(value)
print(my_dict)
方式二:defaultdict字典解决方法
from collections import defaultdict
values = [16, 26, 46, 36, 66, 56, 76, 86, 96, 6]
my_dict = defaultdict(list)
for value in values:
if value > 66:
my_dict['k1'].append(value)
else:
my_dict['k2'].append(value)
print(my_dict)
# 结果:defaultdict(<class 'list'>, {'k2': [16, 26, 46, 36, 66, 56, 6], 'k1': [76, 86, 96]})
使用dict时,如果引用的Key不存在,就会抛出KeyError。如果希望key不存在时,返回一个默认值,就可以用defaultdict:
from collections import defaultdict
d = defaultdict(lambda: 'N/A')
d['name'] = 'Lawrence'
d['name'] # name存在 返回具体值:'Lawrence'
print(d['age']) # age不存在,返回默认值
4. Counter的用法
Counter类的目的是用来跟踪值出现的次数。它是一个无序的容器类型,以字典的键值对形式存储,其中元素作为key,其计数作为value。计数值可以是任意的Interger(包括0和负数)
from collections import Counter
c = Counter(['Lawrence', '小黑', '小梁', '小白', '小红', '小梁', 'Lawrence', 'Chloe', '小黑','小梁'])
print(c)
# 结果:Counter({'小梁': 3, 'Lawrence': 2, '小黑': 2, '小白': 1, '小红': 1, 'Chloe': 1})
创建
下面的代码说明了Counter类创建的四种方法:
Counter类的创建
from collections import Counter
c1 = Counter() # 创建一个空的Counter类
c2 = Counter('iterable') # 从一个可iterable对象(list、tuple、dict、字符串等)创建
c3 = Counter({'a': 4, 'b': 2, 'c': 5}) # 从一个字典对象创建
c4 = Counter(a=4, b=2, c=5) # 从一组键值对创建
计数值的访问与缺失的键
当所访问的键不存在时,返回0,而不是KeyError;否则返回它的计数。
计数值的访问
from collections import Counter
c = Counter(['Lawrence', '小黑', '小梁', '小白', '小红', '小梁', 'Lawrence', 'Chloe', '小黑', '小梁'])
print(c.keys()) # dict_keys(['Lawrence', '小黑', '小梁', '小白', '小红', 'Chloe'])
print(c.values()) # dict_values([2, 2, 3, 1, 1, 1])
print(c['小蓝']) # 没有返回0
计数器的更新(update和subtract)
可以使用一个iterable对象或者另一个Counter对象来更新键值。
计数器的更新包括增加和减少两种。其中
增加使用update()方法:
计数器的更新(update)
from collections import Counter
c = Counter('which')
c.update('where') # 使用另一个iterable对象更新
print(c['h'])
print(c)
d = Counter('watch')
c.update(d) # 使用另一个Counter对象更新
print(c['h'])
print(c)
减少则使用subtract()方法:
计数器的更新(subtract)
from collections import Counter
c = Counter(['Lawrence', '小黑', '小红', '小白', '小红', '小梁', 'Lawrence', 'Chloe', '小黑', '小梁', '小黑'])
c.subtract(['小白']) # 使用另一个iterable对象更新
print(c) # Counter({'小黑': 3, 'Lawrence': 2, '小红': 2, '小梁': 2, 'Chloe': 1, '小白': 0})
d = Counter(['小蓝', '小红'])
c.subtract(d) # 使用另一个Counter对象更新
print(c) # Counter({'小黑': 3, 'Lawrence': 2, '小梁': 2, '小红': 1, 'Chloe': 1, '小白': 0, '小蓝': -1})
键的修改和删除
当计数值为0时,并不意味着元素被删除,删除元素应当使用del。
键的删除
from collections import Counter
c = Counter('abcddfscba')
print(c)
c['b'] = 0
print(c)
del c['a']
print(c)
elements()的用法
返回一个迭代器。元素被重复了多少次,在该迭代器中就包含多少个该元素。元素排列无确定顺序,个数小于1的元素不被包含。
elements()方法:
from collections import Counter
c = Counter(a=4, b=2, c=0, d=-2, e=7)
l_c = list(c.elements()) # ['a', 'a', 'a', 'a', 'b', 'b', 'e', 'e', 'e', 'e', 'e', 'e', 'e']
print(l_c)
most_common([n])
返回一个TopN列表。如果n没有被指定,则返回所有元素。当多个元素计数值相同时,排列是无确定顺序的。
most_common()方法:
from collections import Counter
c = Counter('abracasdddabra')
print(c.most_common())
print(c.most_common(3))
# 结果:
# [('a', 5), ('d', 3), ('b', 2), ('r', 2), ('c', 1), ('s', 1)]
# [('a', 5), ('d', 3), ('b', 2)]
浅拷贝copy
from collections import Counter
c = Counter('0311')
print(c) # Counter({'1': 2, '0': 1, '3': 1})
d = c.copy()
print(d) # Counter({'1': 2, '0': 1, '3': 1})
算术和集合操作
+、-、&、|操作也可以用于Counter。其中&和|操作分别返回两个Counter对象各元素的最小值和最大值。需要注意的是,得到的Counter对象将删除小于1的元素。
Counter对象的算术和集合操作
from collections import Counter
c = Counter(a=3, b=1)
d = Counter(a=1, b=4)
print(c + d) # c[x] + d[x]
# Counter({'b': 5, 'a': 4})
print(c - d) # subtract(只保留正数计数的元素)
# Counter({'a': 2})
print(c & d) # 交集: min(c[x], d[x])
# Counter({'a': 1, 'b': 1})
print(c | d) # 并集: max(c[x], d[x])
# Counter({'b': 4, 'a': 3})
其他常用操作
下面是一些Counter类的常用操作,来源于Python官方文档
Counter类常用操作
list(c) # 将c中的键转为列表
set(c) # 将c中的键转为set
dict(c) # 将c中的键值对转为字典
c.items() # 转为(elem, cnt)格式的列表
Counter(dict(list_of_pairs)) # 从(elem, cnt)格式的列表转换为Counter类对象
c.most_common()[:-n:-1] # 取出计数最少的n个元素
c += Counter() # 移除0和负值