【Python】白话理解:计数器collections.Counter

(1)浅层认知

collections是python内建标准库的集合模块,功能十分强大。
Counter是模块中的计数器对象,其是字典的子类,它会自动统计传给它的可迭代对象重复元素次数。其键是被计数元素,值是该元素出现次数。

(2)Counter是专为计数而生的dict

(2-1)通过初始化方法认知:万物皆可迭代

from collections import Counter
cnt = Counter()

>> Counter()
from collections import Counter
cnt = Counter('Hello World')

>> Counter({'l':3,'o':2,'H':1,'e':1,'W':1,'r':1,'d':1})
from collections import Counter
cnt = Counter({'a':1,'b':2,'d':3,'c':2)

>> Counter({'d':3,'b':2,'c':1,'a':1})
from collections import Counter
cnt = Counter(a=1, b=2, d=3, c=2)

>> Counter({'d':3,'b':2,'c':1,'a':1})

通过上述的4个例子,我们观察不难发现,Counter会自动统计传给它的可迭代对象重复元素次数,并最后按从大到小的顺序排列。

(2-2)访问字典不存在的键,不会报错

如同我前面的文章整理过的文章【Python】白话理解:默认字典collections.defaultdict,最初的目的,是为了保证空值安全返回,而不会使程序中断。
如果访问普通字典不存在的键,系统会报错,同样的场景,如果我们访问Counter计数器对象的不存在的键,它会返回0。

from collections import Counter
cnt = Counter({'a': 1, 'b': 2, 'c': 3})
print(cnt)
>> Counter({'c': 3, 'b': 2, 'a': 1})

# 尝试访问 Counter 中不存在的键
print(cnt['d'])
>> 0

(2-3)字典方法update() 的差异用法

Counter 对象与 dict 对象同样实现了 update() 方法。使用 update() 方法能够将作为参数的字典合并到调用该方法的 dict 对象中。不同的是,dict 对象的 update() 方法在遇到具有相同的键时,将会对该键对应的值执行 覆盖 操作。而 Counter 对象的 update() 方法在遇到具有相同的键时,将会对该键对应的值执行 叠加 操作。对此,请参考如下示例:

from collections import Counter
cnt = Counter()

>> Counter()
from collections import Counter
# Python 中内置的 dict 对象
d = dict([('a', 1), ('b', 2), ('c', 3)])
print(d)
>>{'a': 1, 'b': 2, 'c': 3}

d.update({'a': 4})
print(d)
>>{'a': 4, 'b': 2, 'c': 3}

# ==========
# Counter 对象
cnt = Counter({'a': 1, 'b': 2, 'c': 3})
print(cnt)
>>Counter({'c': 3, 'b': 2, 'a': 1})

cnt.update({'a': 4})
print(cnt)
>>Counter({'a': 5, 'c': 3, 'b': 2})

(3)计数器特有的方法

(3-1)most_common():获取最多的前几个元素

from collections import Counter
cnt = Counter({'a': 1, 'b': 2, 'c': 3})
print(cnt)
>>Counter({'c': 3, 'b': 2, 'a': 1})

# 返回由 Counter 中计数值最大的两个
# 键值对构成的元组所组成的列表
print(cnt.most_common(2))
>>[('c', 3), ('b', 2)]

# 返回由 Counter 中计数值最大的
# 键值对构成的元组所组成的列表
print(cnt.most_common(1))
>>[('c', 3)]

# 未指定,输出所有
print(cnt.most_common())
>>[('c', 3), ('b', 2), ('a', 1)]

(3-2)elements():以列表形式,按次数,输出所有元素

from collections import Counter
cnt = Counter({'a': 1, 'b': 2, 'c': 3, 'd': -4})
print(cnt)
>>Counter({'c': 3, 'b': 2, 'a': 1, 'd': -4})

print(list(cnt.elements()))
>>['a', 'b', 'b', 'c', 'c', 'c']

请注意:输出的顺序,是按创建时首次录入键的先后顺序,也就是创建时{‘a’: 1, ‘b’: 2, ‘c’: 3, ‘d’: -4}的顺序,a\b\c\d。

(3-3)total():所有计数累加

from collections import Counter
cnt = Counter({'a': 1, 'b': 2, 'c': 3, 'd': -4})
cnt1 = Counter('Hello World')
print(cnt.total())
>>2
print(cnt1.total())
>>11

请注意:负数也会加和,所以第一个1+2+3+(-4)=2,但实际上,计数为负数并没有任何意义(因此后面的很多方法都会不显示小于0甚至是等于0的键值对)

(3-4)subtract():给当前计数器减去一组迭代对象

from collections import Counter
cnt = Counter({'a': 1, 'b': 2, 'c': 3, 'd': -4})

cnt.subtract({'a': 0, 'b': 1, 'd': -11})
print(cnt)
>>Counter({'d': 7, 'c': 3, 'a': 1, 'b': 1})

请注意:结果仍然是降序排列,以cnt为基底。

(4)计数器运算

(4-1)计数器间加法

from collections import Counter
 
cnt = Counter('Hello')
cnt1 = Counter('World')
 
print(cnt)
>>Counter({'l': 2, 'H': 1, 'e': 1, 'o': 1})
print(cnt1)
>>Counter({'W': 1, 'o': 1, 'r': 1, 'l': 1, 'd': 1})
print(cnt + cnt1)
>>Counter({'l': 3, 'o': 2, 'H': 1, 'e': 1, 'W': 1, 'r': 1, 'd': 1})

请注意:结果仍然是降序排列,可以理解为此时生成了cnt3。

(4-2)计数器间减法

from collections import Counter
 
cnt = Counter('cook')
cnt1 = Counter('coder')
 
print(cnt)
>>Counter({'o': 2, 'c': 1, 'k': 1})
print(cnt1)
>>Counter({'c': 1, 'o': 1, 'd': 1, 'e': 1, 'r': 1})
print(cnt - cnt1)
>>Counter({'o': 1, 'k': 1})

请注意:可以理解为此时生成了cnt3,但因为小于等于0的计数无统计意义,因此只显示所有大于0的键值对

(4-3)计数器间并集

from collections import Counter

cnt = Counter('Hello')
cnt1 = Counter('World')

print(cnt)
>>Counter({'l': 2, 'H': 1, 'e': 1, 'o': 1})
print(cnt1)
>>Counter({'W': 1, 'o': 1, 'r': 1, 'l': 1, 'd': 1})
print(cnt | cnt1)
>>Counter({'l': 2, 'H': 1, 'e': 1, 'o': 1, 'W': 1, 'r': 1, 'd': 1})

请注意:并集会把所有键都记录在内,值取其中的最大值。

(4-4)计数器间交集

from collections import Counter

cnt = Counter('Hello')
cnt1 = Counter('World')

print(cnt)
>>Counter({'l': 2, 'H': 1, 'e': 1, 'o': 1})
print(cnt1)
>>Counter({'W': 1, 'o': 1, 'r': 1, 'l': 1, 'd': 1})
print(cnt & cnt1)
>>Counter({'l': 1, 'o': 1})

请注意:交会把共同拥有的键记录在内,值取其中的最小值。

(4-5)计数器单目加减运算

from collections import Counter

cnt = Counter({'a': 4, 'b': 3, 'd': 0, 'c': -5})
print(+cnt)
>>Counter({'a': 4, 'b': 3})
print(-cnt)
>>Counter({'c': 5})

请注意:可以理解为是一个空计数器+cnt(或者-cnt),那么就回归到了,计数器间的加减运算。但因为小于等于0的计数无统计意义,因此只显示所有大于0的键值对

(4-6)计数器间的比较运算

比较运算无非是这6种:

  • <
  • >
  • ==
  • <=
  • >=
  • !=
    无论是哪一种,都是左右两个计数器间相同的键 均满足判断关系,如果两者之间某一个不存该键,该键的值即为0,所以总是能一一对应的。举个例子来说,如果是>判断,必须每个对应的键,左边的都要大于右边的。
from collections import Counter

cnt = Counter({'a': 4, 'b': 3, 'd': 7, 'c': 5})
cnt1 = Counter({'c': 3, 'd': 2, 'b': 6, 'a': 4})
cnt2 = Counter({'c': 4, 'd': 6, 'b': 2, 'a': 3})

print(cnt > cnt1)
>> False
print(cnt > cnt2)
>> True

参考引用:

  • 21
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值