【Python】详解 collections.Counter

目录

一、绪论

二、Counter 类

2.1 创建 Counter 对象

2.2 数值访问(键-值索引)

2.3 元素删除 (键-值对删除)

2.4 update() / subtract() —— 元素更新 (键-值对增减)

2.5 elements() —— 元素全部列出

2.6 most_common() —— 元素按出现频数从大到小列出

2.7 算术与集合运算

2.8 常用操作范例


一、绪论

collections 作为 Python 的内建集合模块,实现了许多十分高效的特殊容器数据类型,即除了 Python 通用内置容器: dict、list、set 和 tuple 等的替代方案。在 IDLE 输入 help(collections) 可查看帮助文档,其中常见的类/函数如下:

名称功能
namedtuple用于创建具有命名字段的 tuple 子类的 factory 函数 (具名元组)
deque类似 list 的容器,两端都能实现快速 append 和 pop (双端队列)
ChainMap类似 dict 的类,用于创建多个映射的单视图
Counter用于计算 hashable 对象的 dict 子类 (可哈希对象计数)
OrderedDict记住元素添加顺序的 dict 子类 (有序字典)
defaultdictdict 子类调用 factory 函数来提供缺失值
UserDict包装 dict 对象以便于 dict 的子类化
UserList包装 list 对象以便于 list 的子类化
UserString包装 string 对象以便于 string 的子类化

而本文详述的对象为 hashable 对象计数器 —— Counter 。


二、Counter 类

Counter,顾名思义是一个 计数器。Counter 类作为一个无序的容器类型,以字典的 key-value 对形式存储元素,旨在统计各元素 (哈希项) 出现的次数。具体而言,key 表示元素,value 表示各元素 key 出现的次数,可为任意整数 (即包括0与负数)。Counter 类有时被称为 bags 或 multisets 。我们在 IDLE 通过 help(collections.Counter) 可查看帮助文档。

在 Python 3.7 版更新后,作为 dict 的子类,Counter 继承了记住插入顺序的功能。 Counter 对象进行数学运算时同样会保持顺序。 结果会先按每个元素在运算符左边的出现时间排序,然后再按其在运算符右边的出现时间排序。


2.1 创建 Counter 对象

实例化 Counter 的常见方式为:

## 导入 Counter 类
>>> from collections import Counter  # class collections.Counter([iterable-or-mapping])

>>> hashmap1 = Counter()  # a new, empty counter
>>> hashmap1
Counter()

## 通过可迭代对象、映射和关键字参数等实例化 Counter 对象
>>> hashmap2 = Counter('happy')  # a new counter from an iterable
>>> hashmap2
Counter({'p': 2, 'h': 1, 'a': 1, 'y': 1})

>>> hashmap3 = Counter(['A', 'A', 'K', 4, 7, 7])  # a new counter from an iterable
>>> hashmap3
Counter({'A': 2, 'K': 1, 4: 1, 7: 2})

>>> hashmap4 = Counter(('M', 'M', 4, 'A', 1, 1))  # a new counter from an iterable
>>> hashmap4
Counter({'M': 2, 4: 1, 'A': 1, 1: 2})

>>> hashmap5 = Counter({'x':1, 'y':2})  # a new counter from a mapping
>>> hashmap5
Counter({'y': 2, 'x': 1})

>>> hashmap6 = Counter(kangkang=1, daming=2, sam=3)  # a new counter from keyword args
>>> hashmap6
Counter({'sam': 3, 'daming': 2, 'kangkang': 1})

# 类型检查
>>> type(hashmap1), type(hashmap2), type(hashmap3), type(hashmap4), type(hashmap5), type(hashmap6)
(<class 'collections.Counter'>, <class 'collections.Counter'>, <class 'collections.Counter'>, <class 'collections.Counter'>, <class 'collections.Counter'>), <class 'collections.Counter'>)

可见元素从一个 iterable 被计数或从其他的 mapping (or counter) 实现初始化。


2.2 数值访问(键-值索引)

Counter 对象类似于 dict 接口,也通过 key 索引访问 value,但注意返回的 value 表示的是 key 的计数值

>>> hashmap2['p']  # hashmap2 = Counter({'p': 2, 'h': 1, 'a': 1, 'y': 1})
2

>>> hashmap3['A']  # hashmap3 = Counter({'A': 2, 'K': 1, 4: 1, 7: 2})
2

>>> hashmap4['M']  # hashmap4 = Counter({'M': 2, 4: 1, 'A': 1, 1: 2})
2

>>> hashmap5['x']  # hashmap5 = Counter({'y': 2, 'x': 1})
1

当访问的 key 不存在时,返回 0 而非 KeyError:

# count of a missing element is zero
>>> hashmap2[6]  # hashmap2 = Counter({'p': 2, 'h': 1, 'a': 1, 'y': 1})
0
>>> hashmap3[6]  # hashmap3 = Counter({'A': 2, 7: 2, 'K': 1, 4: 1})
0
>>> hashmap4[6]  # hashmap4 = Counter({'M': 2, 1: 2, 4: 1, 'A': 1})
0
>>> hashmap5[6]  # hashmap5 = Counter({'y': 2, 'x': 1})
0

作为 dict 的子类,通过 Counter.keys()、Counter.values()、Counter.items() 访问键-值对仍然适用:

# 以 hashmap2 为例
>>> hashmap2 = Counter('happy')
>>> hashmap2 
Counter({'p': 2, 'h': 1, 'a': 1, 'y': 1})

>>> hashmap2.keys()
dict_keys(['h', 'a', 'p', 'y'])
>>> type(hashmap2.keys())
<class 'dict_keys'>

>>> hashmap2.values()
dict_values([1, 1, 2, 1])
>>> type(hashmap2.values())
<class 'dict_values'>

>>> hashmap2.items()
dict_items([('h', 1), ('a', 1), ('p', 2), ('y', 1)])
>>> type(hashmap2.items())
<class 'dict_items'>

注意,原地操作如 hashmap[key] += 1,值类型只支持加和减,故分数、小数、十进制甚至负值都适用。


2.3 元素删除 (键-值对删除)

对于 Counter 对象的元素删除应使用内置函数 del,而令 value=0 是不能删除元素(键-值对)的。

# 以 hashmap2 为例
>>> hashmap2 = Counter('happy')
>>> hashmap2 
Counter({'p': 2, 'h': 1, 'a': 1, 'y': 1})

>>> hashmap2['y'] = 0
>>> hashmap2
Counter({'p': 2, 'h': 1, 'a': 1, 'y': 0})  # 'y' 还在, 只是 value=0 而已

>>> del hashmap2['y']
>>> hashmap2
Counter({'p': 2, 'h': 1, 'a': 1})  # 'y' 被删除了

2.4 update() / subtract() —— 元素更新 (键-值对增减)

可以使用另外的 iterable 对象或 Counter 对象实现对原 Counter 对象的元素更新 (键-值对增减)。

其中,元素增加使用 Counter.update(iterable-or-mapping) 方法:

## 以 hashmap2 为例, 其余同理
>>> hashmap2 = Counter('happy')
>>> hashmap2 
Counter({'p': 2, 'h': 1, 'a': 1, 'y': 1})

## 用 iterable 对象更新
>>> hashmap2.update('hp')  # 用 string 更新 (iterable 对象)
>>> hashmap2
Counter({'p': 3, 'h': 2, 'a': 1, 'y': 1})  
 
>>> hashmap2.update(['a','y'])  # 用 list 更新 (iterable 对象)
>>> hashmap2
Counter({'p': 3, 'h': 2, 'a': 2, 'y': 2})

>>> hashmap2.update(('a'))  # 用 tuple 更新 (iterable 对象)
>>> hashmap2
Counter({'a': 3, 'p': 3, 'h': 2, 'y': 2})

## 用 mapping 对象更新
>>> hashmap2.update({'h':1, 'y':1})  # 用 dict 更新 (mapping 对象)
>>> hashmap2
Counter({'h': 3, 'a': 3, 'p': 3, 'y': 3})

## 用 Counter 对象更新
>>> hashmap2.update(Counter('hapy'))
>>> hashmap2
Counter({'h': 4, 'a': 4, 'p': 4, 'y': 4})

注意,元素的添加来自 iterable 对象计数元素,或另一个 mapping 对象 (或 Counter 对象) ,其中 iterable 对象应为序列 sequence 元素。

同理,元素减少使用 Counter.subtract(iterable-or-mapping) 方法,但注意元素的计数 —— value 为 0 和 负数都是允许的

# 以 hashmap2 为例, 其余同理
>>> hashmap2 = Counter('happy')
>>> hashmap2 
Counter({'p': 2, 'h': 1, 'a': 1, 'y': 1})

# 用 iterable 对象更新元素
>>> hashmap2.subtract('p')  # 用 string 更新
>>> hashmap2
Counter({'h': 1, 'a': 1, 'p': 1, 'y': 1}) 

>>> hashmap2.subtract(['p'])  # 用 list 更新
>>> hashmap2
Counter({'h': 1, 'a': 1, 'p': 0, 'y': 1})  # 允许 value <= 0

>>> hashmap2.subtract(('p'))  # 用 tuple 更新
>>> hashmap2
Counter({'h': 1, 'a': 1, 'y': 1, 'p': -1})  # 允许 value <= 0

## 用 mapping 对象更新
>>> hashmap2.subtract({'h':2})  # 用 dict 更新
>>> hashmap2
Counter({'a': 1, 'y': 1, 'h': -1, 'p': -1})  # 允许 value <= 0

## 用 Counter 对象更新
>>> hashmap2.update(Counter('ay'))
>>> hashmap2
Counter({'a': 0, 'y': 0, 'h': -1, 'p': -1})

可见使用 iterable 对象更新原 Counter 对象之前,都会被隐式地转换为 Counter 对象,再把元素更新到原 Counter 对象上。


2.5 elements() —— 元素全部列出

Counter.elements() 方法将返回一个迭代器。元素的计数有多少,在该迭代器中就包含多少个该元素。元素排列无确定顺序 元素按首次出现的顺序返回,且不含 value<= 0 的元素

>>> hashmap7 = Counter('happy')
>>> hashmap7
Counter({'p': 2, 'h': 1, 'a': 1, 'y': 1})

>>> hashmap7.elements()          # 返回迭代器
<itertools.chain object at 0x00000249719226A0>

>>> list(hashmap7.elements())    # 显式类型转换
['h', 'a', 'p', 'p', 'y']

>>> tuple(hashmap7.elements())   # 显式类型转换
('h', 'a', 'p', 'p', 'y')

>>> str(hashmap7.elements())     # 那是不可能的...
'<itertools.chain object at 0x0000024971125390>'

>>> sorted(hashmap7.elements())  # 隐式类型转换
['a', 'h', 'p', 'p', 'y']

2.6 most_common() —— 元素按出现频数从大到小列出

Counter.most_common([n]) 方法将返回一个 list,其中包含前 n 个出现频数最高的元素及其出现次数,并从大到小排列。 若 n 被省略或为 None,most_common()  将返回 Counter 对象中的所有元素。若元素计数值相等,则按首次出现的顺序排序:

>>> hashmap8 = Counter(x=3, y=2, z=1, h=2)
>>> hashmap8
Counter({'x': 3, 'y': 2, 'h': 2, 'z': 1})

>>> hashmap8.most_common(1)  # n=1
[('x', 3)]
>>> hashmap8.most_common(2)  # n=2
[('x', 3), ('y', 2)]
>>> hashmap8.most_common(3)  # n=3
[('x', 3), ('y', 2), ('h', 2)]
>>> hashmap8.most_common(4)  # n=4
[('x', 3), ('y', 2), ('h', 2), ('z', 1)]  # 'y' 与 'h' 出现频次均为 2, 但 'y' 先出现, 故前排

>>> hashmap8.most_common()  # n ignored
[('x', 3), ('y', 2), ('h', 2), ('z', 1)]  # 全排:从大到小
>>> hashmap8.most_common()[::-1]  # n ignored
[('z', 1), ('h', 2), ('y', 2), ('x', 3)]  # 全排:从小到大

2.7 算术与集合运算

有几个常用的数学运算操作:

>>> h1 = Counter(x=1, y=2)
>>> h2 = Counter(x=2, y=1)
>>> h3 = Counter(x=1, y=-1)

>>> h1 + h2
Counter({'x': 3, 'y': 3})  # 按元素相加
>>> h2 + h3
Counter({'x': 3})  # value <= 0 的会被删除

>>> h1 - h2
Counter({'y': 1})  # 按元素相减
>>> h1 - h3
Counter({'y': 3})  # value <= 0 的会被删除

>>> h1 & h2
Counter({'x': 1, 'y': 1})  # 按元素取 min() (交集)

>>> h1 | h2
Counter({'x': 2, 'y': 2})  # 按元素取 max() (并集)

        还有单目加和减 (一元操作符) 及其等价形式:

>>> hashmap9 = Counter(a=2, b=1, c=0, d=-1)

>>> +hashmap9
Counter({'a': 2, 'b': 1})  # 去除 value<=0 的元素

>>> -hashmap9
Counter({'d': 1})  # 去除 value>=0 的元素

>>> hashmap9 += Counter()  
>>> hashmap9
Counter({'a': 2, 'b': 1})  # 去除 value<=0 的元素 

2.8 常用操作范例

>>> hashmap8 = Counter(x=3, y=2, z=1, h=2)
>>> hashmap8
Counter({'x': 3, 'y': 2, 'h': 2, 'z': 1})

## 对 Counter 对象的 value 求和
>>> sum(hashmap8.values())  
8

## 从小到大排序
>>> hashmap8.most_common()[::-1]
[('z', 1), ('h', 2), ('y', 2), ('x', 3)]  

## 类型转换
>>> list(hashmap8)
['x', 'y', 'z', 'h']  # 将 Counter 对象的 key 转换为 list
>>> tuple(hashmap8)
('x', 'y', 'z', 'h')  # 将 Counter 对象的 key 转换为 tuple
>>> set(hashmap8)
{'z', 'y', 'x', 'h'}  # 将 Counter 对象的 key 转换为 set
>>> dict(hashmap8)
{'x': 3, 'y': 2, 'z': 1, 'h': 2}  # 将 Counter 对象的转换为 dict

## 去除 value <= 0 的元素
>>> hashmap9 = Counter(a=2, b=1, c=0, d=-1)
>>> hashmap9
Counter({'a': 2, 'b': 1, 'c': 0, 'd': -1})

>>> hashmap9 += Counter()  
>>> hashmap9
Counter({'a': 2, 'b': 1})

参考文献

《Python Immediate》

collections --- 容器数据类型 — Python 3.10.4 文档

collections - 廖雪峰的官方网站

<think>好的,我现在需要回答用户关于Pythoncollections.Counter的元素及其用法的问题。首先,我需要回忆一下自己对Counter的了解,并结合提供的引用内容来组织答案。 用户的问题包括了解Counter的元素、使用方法和官方文档示例。根据引用内容,比如引用[1]提到Counter用于计数可哈希对象,引用[4]和[5]也说明了其基本用法和应用场景。我需要确保覆盖以下几个方面: 1. **基本概念**:说明Counter是什么,它的主要作用是什么。比如,它是一个计数器,用于统计可哈希对象的出现次数,类似于其他语言中的bag或multiset。 2. **创建方法**:用户可能需要知道如何初始化一个Counter对象。根据引用[5]中的示例,可以通过传递可迭代对象(如列表、字符串)或者字典来创建。 3. **常用方法**:需要列举常用的方法,比如elements(), most_common(n), subtract(), update()等,并给出示例。引用[3]和[4]中提到了这些方法的使用。 4. **数学运算**:Counter支持加减运算,引用[2]中的例子展示了如何通过减法判断ransomNote是否可以由magazine构成,这说明减法的使用方式。 5. **应用场景**:引用[1]和[4]提到了数据分析、文本处理和算法中的应用,这部分需要具体举例说明,比如统计词频或元素频率。 6. **官方文档**:需要提及用户如何查阅官方文档,可能给出链接或简要说明官方文档中的内容结构。 在组织内容时,要遵循用户给出的格式要求,比如行内公式用$...$,独立公式用$$...$$,不过这个问题可能不涉及数学公式,但需要检查是否有数学表达式需要注意。此外,要使用中文回答,结构清晰,分步骤解释,并在适当的位置添加引用标识。 需要确认引用对应的内容是否正确。例如,引用[2]中的代码使用了Counter来比较两个字符串的字符计数,这可以用来展示Counter的减法操作。而引用[5]提到了基本用法,可以用于创建部分的说明。 需要注意避免直接复制引用内容,而是用自己的话重新组织,同时确保信息准确。例如,创建Counter对象时,可以传递列表、字符串或字典,而elements()方法会返回所有元素的迭代器,每个元素重复其计数次数。 还需要检查是否有遗漏的重要方法或特性,比如Counter对缺失键的处理(默认返回0而不是KeyError),或者使用update()来合并计数。这些点可能在引用中没有明确提到,但根据我的知识需要补充进去。 最后,生成相关问题,确保问题与Counter相关,并覆盖其使用、优化、应用等方面。例如,如何合并两个Counter,或者如何处理大量数据的计数优化。 总结步骤: 1. 介绍Counter的基本概念和作用。 2. 详细说明如何创建Counter对象,包括不同的初始化方式。 3. 列举常用方法,每个方法给出简短说明和示例代码。 4. 解释支持的数学运算及其应用。 5. 讨论典型应用场景,结合引用中的例子。 6. 提供官方文档的参考信息。 7. 生成相关问题,确保覆盖可能的相关知识点。 现在需要将这些内容结构化,按照用户提供的示例中的格式,使用标题、代码块、列表等元素,使回答清晰易读。同时确保所有引用正确标注,比如在提到减法操作时引用[2],在创建方法时引用[5]等。</think>### Pythoncollections.Counter的元素及用法详解 #### 1. Counter的基本概念 `collections.Counter` 是Python标准库中用于**计数可哈希对象**的容器类。它通过字典形式存储元素及其出现次数,键为元素,值为计数,常用于数据分析、文本处理等场景[^1][^4]。 与普通字典不同,当查询未存在的键时,`Counter` 返回0而非抛出`KeyError`[^5]。 #### 2. 创建Counter对象 可以通过以下方式初始化: ```python from collections import Counter # 方式1: 通过可迭代对象(如列表、字符串) c1 = Counter(['a', 'b', 'a', 'c']) # → Counter({'a':2, 'b':1, 'c':1}) c2 = Counter("hello") # → Counter({'h':1, 'e':1, 'l':2, 'o':1}) # 方式2: 通过字典指定键值对 c3 = Counter({'a':3, 'b':2}) # → Counter({'a':3, 'b':2}) # 方式3: 通过关键字参数 c4 = Counter(a=2, b=4) # → Counter({'b':4, 'a':2}) ``` #### 3. 常用方法及示例 | 方法名 | 功能描述 | 示例代码 | |--------------------|------------------------------------------------------------------------|--------------------------------------------------------------------------| | `elements()` | 返回元素迭代器,每个元素重复其计数次 | `list(c1.elements()) → ['a','a','b','c']` | | `most_common(n)` | 返回前`n`个最常见元素及计数 | `c2.most_common(2) → [('l',2), ('h',1)]` | | `subtract(iterable)`| 从计数中减去参数中的元素 | `c1.subtract(['a','b']) → Counter({'a':1, 'b':0, 'c':1})` | | `update(iterable)` | 合并参数中的元素计数(类似加法) | `c1.update({'a':3}) → Counter({'a':5, 'b':1, 'c':1})` | #### 4. 数学运算支持 - **加法(+)**:合并两个`Counter`,计数相加。 - **减法(-)**:从计数中减去,结果仅保留正计数。 - **交集(&)**:取两者共有的键,计数取较小值。 - **并集(|)**:取所有键,计数取较大值。 **示例**:判断字符串`ransomNote`能否由`magazine`的字符构成[^2] ```python def canConstruct(ransomNote: str, magazine: str) -> bool: return not (Counter(ransomNote) - Counter(magazine)) ``` #### 5. 应用场景 - **词频统计**:统计文本中单词出现次数。 - **数据清洗**:过滤低频或高频元素(如使用`most_common()`)。 - **算法优化**:快速比较元素分布(如上述字符串构造问题)[^4]。 #### 6. 官方文档参考 Python官方文档详细说明了`Counter`的所有方法和特性[^5]: 📖 [Python Collections文档](https://docs.python.org/3/library/collections.html#collections.Counter) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值