详解Python中非常好用的计数器Counter
详解Python中非常好用的计数器Counter
Counter简介Counter是Python内置模块collections中的一个计数器工具,可以方便快捷地计数。
Counter是字典dict的子类,用于计数可哈希(hashable)对象。(Python中实现了魔法方法__hash__的对象是hashable对象,关于可哈希和不可哈希,可以自行搜索了解,后面有时间我可以再专门写文章详细介绍)
Counter是一个多项集,元素被存储为字典的键,元素的计数被存储为字典的值。计数可以是任何整数,包括零或负数。(甚至也可以是小数,不过本文不对此展开讨论。)
Counter计数器的优点:
用法简单:它可以通过一个可迭代对象(iterable)来初始化,用一个映射(mapping)对象(包括Counter本身)来初始化,用键值对来初始化,或者直接创建一个空的Counter实例。
访问不存在的元素不报错:Counter对象的接口类似于字典,不同的是,如果查询的键不在Counter中,它会返回0,而不是抛出KeyError异常。相当于对任意键都有一个默认值0,这可以在一些遍历搜索的代码中避免程序报错。(严格来说,不报错有利有弊,不过在计数这种场景利大于弊,程序设计团队肯定也权衡过。)
支持的方法很多:作为dict的子类,Counter继承了dict的大部分方法,此外还实现了一些非常便利的方法。Counter也可以转换成列表、集合、字典等Python内置数据类型,从而使用这些数据类型的方法,如切片操作等。
接下来,本文将详细对Counter的各种特性和功能进行逐一介绍。
计数器功能实现假设要统计一个列表[1, 2, 3, 4, 5, 1, 2, 3]中各元素出现的次数,可以利用字典,用如下代码实现。
# coding=utf-8 nums = [1, 2, 3, 4, 5, 1, 2, 3] result = dict() for n in nums: if n not in result: result[n] = 1 else: result[n] += 1 print(result) 123456789'
Output:
{1: 2, 2: 2, 3: 2, 4: 1, 5: 1} 1
上面的代码中我们自己新建了一个字典,将待计数的列表nums中的元素作为字典的键,遍历nums,对每个元素进行计数。
Counter的计数功能就类似于上面的代码,创建一个Counter对象即可完成计数。
from collections import Counter nums = [1, 2, 3, 4, 5, 1, 2, 3] print(Counter(nums)) 1234'
Output:
Counter({1: 2, 2: 2, 3: 2, 4: 1, 5: 1}) 1
可以看到,Counter封装了计数功能,只需要把待计数的数据传给Counter计数器,它即可立即返回一个计数器对象,完成对元素的计数。
在需要计数时,可以直接调用Counter来使用,不用再自己写计数的代码。虽然自己写代码也并不复杂,但是更关键的是,Counter除了可以完成计数,还实现了一些非常好用的方法,方便我们对计数器进行更丰富的处理和解析。
Counter初始化的几种方式# 创建一个空计数器,然后用字典的方式给计数器添加值 c = Counter() c['ai'] = 100 print(c) # 实例化时将可迭代对象传入Counter c1 = Counter('pythoncode') print(c1) # 实例化时将映射对象传入Counter c2 = Counter({'a': 5, 'b': 2, 'c': 1}) print(c2) # 实例化时将键值对传入Counter c3 = Counter(A=1, B=2, C=5, D=6, E=7) print(c3) 12345678910111213
Output:
Counter({'ai': 100}) Counter({'o': 2, 'p': 1, 'y': 1, 't': 1, 'h': 1, 'n': 1, 'c': 1, 'd': 1, 'e': 1}) Counter({'a': 5, 'b': 2, 'c': 1}) Counter({'E': 7, 'D': 6, 'C': 5, 'B': 2, 'A': 1}) 1234
在实例化Counter时,可以传入可迭代对象(如字符串、列表),映射类型对象(如字典),键值对等。
访问Counter中不存在的元素如果访问字典中不存在的键,会报错KeyError。例如:
t_dict = {'A': 0, 'K': 3, 'Q': 3, 'J': 1} print(t_dict['KING']) 12
Output:
Traceback (most recent call last): File "..counter_demo.py", line 36, in <module> print(t_dict['KING']) KeyError: 'KING' 1234
在Counter中访问不存在的元素时,会返回0。(这相当于字典用setdefault(key, value)设置了默认值,通过魔法方法__missing__实现。)
t_counter = Counter({'A': 0, 'K': 3, 'Q': 3, 'J': 1}) print(t_counter['KING']) 12
Output:
0 1
对于计数器中不存在的元素,返回的计数值为0,这比较符合生活常识,比报错KeyError友好很多,在一些代码中也有好处。
此外,前面提到过,Counter中的计数还可以是负数,通常情况,计数不会有负数,不过负数也不是完全没有用处,对于一些特殊场景,如需要记录类似“欠账”的情况,负数也可以派上用场。
这里还有一个注意点,Counter中某元素计数为0和Counter中不存在某元素,返回值都为0,代码处理(如访问元素的计数值、执行自增操作等)没有差别,但本质上并不一样,一种是Counter存在该元素,一种是Counter中不存在该元素。
也就是说,如果把Counter中的一个元素的计数值改成0,并不代表从Counter中删除了该元素。
t_counter['J'] = 0 print(t_counter) print('J' in t_counter) print('KING' in t_counter) 1234
Output:
Counter({'K': 3, 'Q': 3, 'A': 0, 'J': 0}) True False 123
要将元素从Counter中删除,跟字典删除方法相同,使用del关键字。
del t_counter['J'] print(t_counter) print('J' in t_counter) 123
Output:
Counter({'K': 3, 'Q': 3, 'A': 0}) False 12 Counter支持的方法
Counter继承了字典的大部分方法,可以直接使用,如常用的keys()、values()、items(),还有copy()、clear()、pop()等等,就不逐一例举了。
本章节主要介绍Counter支持的一些附加方法。
elements(): 返回一个迭代器,其中每个元素都重复计数值所指定的次数。相同的元素会集中在一起,不同元素会按首次出现的顺序排列,如果一个元素的计数值小于1,elements()会将其忽略。
c_counter = Counter(['red', 'pink', 'yellow', 'blue', 'yellow', 'blue', 'pink', 'blue']) print(c_counter.elements()) print(list(c_counter.elements())) 123
Output:
<itertools.chain object at 0x000002569074B970> ['red', 'pink', 'pink', 'yellow', 'yellow', 'blue', 'blue', 'blue'] 12
most_common([n]): 返回一个列表,包含计数值最大的n个元素及其计数,按计数值从高到低排序,如果计数值相等,按元素首次出现的顺序排列。如果n为None(不传值或传None),返回计数器中的所有元素。
c_counter = Counter(['red', 'pink', 'yellow', 'blue', 'yellow', 'blue', 'pink', 'blue']) print(c_counter.most_common()) print(c_counter.most_common(2)) 123
Output:
[('blue', 3), ('pink', 2), ('yellow', 2), ('red', 1)] [('blue', 3), ('pink', 2)] 12
subtract([iterable-or-mapping]): 减去一个可迭代对象或映射对象(包含Counter)中的元素(个数)。具体执行时将每个元素的计数值减去传入元素的计数值,输入输出都可以是0或负数。如果是不存在的元素,用0减。结果中元素的顺序按计数值从高到低排序,如果计数值相等,按元素首次出现的顺序排列。(可以发现,从文章开头,除elements()外,都是按这种顺序排序,本文后面的结果也都是按这种顺序。)
c_counter = Counter(['red', 'pink', 'yellow', 'blue', 'yellow', 'blue', 'pink', 'blue']) print(c_counter) ls = ['blue', 'yellow'] c_counter.subtract(ls) # 减一个列表 print(c_counter) dt = {'pink': 1, 'red': 1, 'green': 1} c_counter.subtract(dt) # 减一个字典 print(c_counter) c2_counter = Counter({'blue': 1, 'yellow': 2, 'green': 3}) c_counter.subtract(c2_counter) # 减另一个Counter print(c_counter) 1234567891011
Output:
Counter({'blue': 3, 'pink': 2, 'yellow': 2, 'red': 1}) Counter({'pink': 2, 'blue': 2, 'red': 1, 'yellow': 1}) Counter({'blue': 2, 'pink': 1, 'yellow': 1, 'red': 0, 'green': -1}) Counter({'pink': 1, 'blue': 1, 'red': 0, 'yellow': -1, 'green': -4}) 1234
update([iterable-or-mapping]): 加上一个可迭代对象或映射对象(包含Counter)中的元素(个数)。具体执行时将每个元素的计数值加上传入元素的计数值,输入和输出都可以是0或负数。
c_counter.update(ls) # 加一个列表 print(c_counter) c_counter.update(dt) # 加一个字典 print(c_counter) c_counter.update(c2_counter) # 加另一个Counter print(c_counter) 123456
Output:
Counter({'blue': 2, 'pink': 1, 'red': 0, 'yellow': 0, 'green': -4}) Counter({'pink': 2, 'blue': 2, 'red': 1, 'yellow': 0, 'green': -3}) Counter({'blue': 3, 'pink': 2, 'yellow': 2, 'red': 1, 'green': 0}) 123
Counter的subtract()和update()是一对互逆的方法,类似于字典的update(),不过Counter中是计数值的相加或相减,而非更新替换。
此外,可迭代对象应当是一个元素序列,不能是一个(key, value)对组成的序列,那样会将整个序列当成一个整体元素处理。
total(): 返回计数器中总的计数值,此方法从Python3.10开始支持,更早的版本不支持。
c_counter = Counter(['red', 'pink', 'yellow', 'blue', 'yellow', 'blue', 'pink', 'blue']) print(c_counter) print(c_counter.total()) 123
Output:
Counter({'blue': 3, 'pink': 2, 'yellow': 2, 'red': 1}) 8 12 Counter的算术运算
cnt1 = Counter({'red': 3, 'green': 2, 'blue': 1}) cnt2 = Counter({'red': 1, 'green': 2, 'blue': 3}) print(cnt1 + cnt2) print(cnt1 - cnt2) 1234
Output:
Counter({'red': 4, 'green': 4, 'blue': 4}) Counter({'red': 2}) 12
两个Counter计数器相加或相减,会将计数器中各元素的计数值进行加减,得到一个新的Counter计数器。
结果中只保留计数大于0的元素,也就是说算术运算前的计数器中可以有0或负数,但结果中不会保留0和负数。
Counter的交并运算cnt1 = Counter({'red': 3, 'green': 2, 'blue': 1}) cnt2 = Counter({'red': 1, 'green': 2, 'blue': 3}) print(cnt1 | cnt2) # 并集 print(cnt1 & cnt2) # 交集 1234
Output:
Counter({'red': 3, 'blue': 3, 'green': 2}) Counter({'green': 2, 'red': 1, 'blue': 1}) 12
Counter的并集运算使用逻辑或的符号 | ,交集使用逻辑与的符号 & 。这里要注意,用Python的关键字 or 和 and 计算的结果不一样,or 和 and 会依次判断两个Counter是否为True,做的是逻辑运算不是交并运算。
计算并集时,结果取相同元素在两个Counter中计数值较大的计数,计算交集时,结果取相同元素在两个Counter中计数值较小的计数。
Counter的比较运算cnt3 = Counter({'red': 20, 'green': 10, 'blue': 0}) cnt4 = Counter({'red': 20, 'green': 10}) print(cnt3 == cnt4) print(cnt4 < cnt3) 1234
Output:
True False 12
Counter之间可以进行比较运算,支持 ==, !=, <, <=, >, >= 。在比较时,如果不存在的元素,会用计数0进行比较,所以上面的cnt3和cnt4相等。对于小于,只要Counter中有一个元素的计数值小于另一个Counter,其他元素的计数值可以相等,此时会返回True。大于同理。
比较运算从Python3.10开始支持,更早的版本不支持。
参考文档:https://docs.python.org/zh-cn/3/library/collections.html#counter-objects
相关阅读:详解Python中的排列组合生成器
欢迎 点赞 收藏⭐ 评论 关注❤ 如有错误敬请指正!
☟ 学Python,点击下方名片关注我。☟
相关知识
Python中is和==的区别详解
【Python】基础
Python中的花——详解花的图形绘制
MOOC —— Python语言基础与应用 by 北京大学 第六章 计算和控制流(二)
《动物森友会》花卉繁殖机制与布局影响分析
Python编程实现花卉图案绘制与色彩搭配技巧详解
Python常见的错误以及其解决方案
ai怎么绘制玫瑰花:详解AI绘制技巧与步骤
python 绘制一个四瓣花图
[Python] 机器学习
网址: 详解Python中非常好用的计数器Counter https://www.huajiangbk.com/newsview893378.html
上一篇: 数字电路基础 |
下一篇: Mpg计算器 |
推荐分享

- 1君子兰什么品种最名贵 十大名 4012
- 2世界上最名贵的10种兰花图片 3364
- 3花圈挽联怎么写? 3286
- 4迷信说家里不能放假花 家里摆 1878
- 5香山红叶什么时候红 1493
- 6花的意思,花的解释,花的拼音 1210
- 7教师节送什么花最合适 1167
- 8勿忘我花图片 1103
- 9橄榄枝的象征意义 1093
- 10洛阳的市花 1039