Skip to content

Commit 2c96bee

Browse files
committed
add collections
1 parent cd95de2 commit 2c96bee

1 file changed

Lines changed: 205 additions & 0 deletions

File tree

Standard-Modules/collections.md

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
# collections
2+
3+
我们知道,Python 的数据类型有 list, tuple, dict, str 等,**collections 模块**提供了额外 5 个高性能的数据类型:
4+
5+
- `Counter`: 计数器
6+
- `OrderedDict`: 有序字典
7+
- `defaultdict`: 带有默认值的字典
8+
- `namedtuple`: 生成可以通过属性访问元素内容的 tuple 子类
9+
- `deque`: 双端队列,能够在队列两端添加或删除元素
10+
11+
# Counter
12+
13+
`Counter` 是一个简单的计数器,可用于统计字符串、列表等的元素个数。
14+
15+
看看例子:
16+
17+
```python
18+
>>> from collections import Counter
19+
>>>
20+
>>> s = 'aaaabbbccd'
21+
>>> c = Counter(s) # 创建了一个 Counter 对象
22+
>>> c
23+
Counter({'a': 4, 'b': 3, 'c': 2, 'd': 1})
24+
>>> isinstance(c, dict) # c 其实也是一个字典对象
25+
True
26+
>>> c.get('a')
27+
4
28+
>>> c.most_common(2) # 获取出现次数最多的前两个元素
29+
[('a', 4), ('b', 3)]
30+
```
31+
32+
在上面,我们使用 `Counter()` 创建了一个 `Counter` 对象 `c``Counter` 其实是 dict 的一个子类,我们可以使用 `get` 方法来获取某个元素的个数。`Counter` 对象有一个 `most_common` 方法,允许我们获取出现次数最多的前几个元素。
33+
34+
另外,两个 `Counter` 对象还可以做运算:
35+
36+
```python
37+
>>> from collections import Counter
38+
>>>
39+
>>> s1 = 'aaaabbbccd'
40+
>>> c1 = Counter(s1)
41+
>>> c1
42+
Counter({'a': 4, 'b': 3, 'c': 2, 'd': 1})
43+
>>>
44+
>>> s2 = 'aaabbef'
45+
>>> c2 = Counter(s2)
46+
>>> c2
47+
Counter({'a': 3, 'b': 2, 'e': 1, 'f': 1})
48+
>>>
49+
>>> c1 + c2 # 两个计数结果相加
50+
Counter({'a': 7, 'b': 5, 'c': 2, 'e': 1, 'd': 1, 'f': 1})
51+
>>> c1 - c2 # c2 相对于 c1 的差集
52+
Counter({'c': 2, 'a': 1, 'b': 1, 'd': 1})
53+
>>> c1 & c2 # c1 和 c2 的交集
54+
Counter({'a': 3, 'b': 2})
55+
>>> c1 | c2 # c1 和 c2 的并集
56+
Counter({'a': 4, 'b': 3, 'c': 2, 'e': 1, 'd': 1, 'f': 1})
57+
```
58+
59+
# OrderedDict
60+
61+
Python 中的 dict 是无序的:
62+
63+
```python
64+
>>> dict([('a', 10), ('b', 20), ('c', 15)])
65+
{'a': 10, 'c': 15, 'b': 20}
66+
```
67+
68+
有时,我们希望保持 key 的顺序,这时可以用 OrderedDict:
69+
70+
```python
71+
>>> from collections import OrderedDict
72+
>>> OrderedDict([('a', 10), ('b', 20), ('c', 15)])
73+
OrderedDict([('a', 10), ('b', 20), ('c', 15)])
74+
```
75+
76+
# defaultdict
77+
78+
在 Python 中使用 dict 时,如果访问了不存在的 key,会抛出 KeyError 异常,因此,在访问之前,我们经常需要对 key 作判断,比如:
79+
80+
```python
81+
>>> d = dict()
82+
>>> s = 'aaabbc'
83+
>>> for char in s:
84+
... if char in d:
85+
... d[char] += 1
86+
... else:
87+
... d[char] = 1
88+
...
89+
>>> d
90+
{'a': 3, 'c': 1, 'b': 2}
91+
```
92+
93+
使用 defaultdict,我们可以给字典中的 key 提供一个默认值。访问 defaultdict 中的 key,如果 key 存在,就返回 key 对应的 value,如果 key 不存在,就返回默认值。
94+
95+
```python
96+
>>> from collections import defaultdict
97+
>>> d = defaultdict(int) # 默认的 value 值是 0
98+
>>> s = 'aaabbc'
99+
>>> for char in s:
100+
... d[char] += 1
101+
...
102+
>>> d
103+
defaultdict(<type 'int'>, {'a': 3, 'c': 1, 'b': 2})
104+
>>> d.get('a')
105+
3
106+
>>> d['z']
107+
0
108+
```
109+
110+
使用 defaultdict 时,我们可以传入一个工厂方法来指定默认值,比如传入 int,表示默认值是 0,传入 list,表示默认是 `[]`
111+
112+
```python
113+
>>> from collections import defaultdict
114+
>>>
115+
>>> d1 = defaultdict(int)
116+
>>> d1['a']
117+
0
118+
>>> d2 = defaultdict(list)
119+
>>> d2['b']
120+
[]
121+
>>> d3 = defaultdict(str)
122+
>>> d3['a']
123+
''
124+
```
125+
126+
我们还可以自定义默认值,通过 `lambda` 函数来实现:
127+
128+
```python
129+
>>> from collections import defaultdict
130+
>>>
131+
>>> d = defaultdict(lambda: 10)
132+
>>> d['a']
133+
10
134+
```
135+
136+
# namedtuple
137+
138+
我们经常用 tuple (元组) 来表示一个不可变对象,比如用一个 `(姓名, 学号, 年龄)` 的元组来表示一个学生:
139+
140+
```python
141+
>>> stu = ('ethan', '001', 20)
142+
>>> stu[0]
143+
'ethan'
144+
```
145+
146+
这里使用 tuple 没什么问题,但可读性比较差,我们必须清楚索引代表的含义,比如索引 0 表示姓名,索引 1 表示学号。如果用类来定义,就可以通过设置属性 name, id, age 来表示,但就有些小题大作了。
147+
148+
我们可以通过 namedtuple 为元组的每个索引设置名称,然后通过「属性名」来访问:
149+
150+
```python
151+
>>> from collections import namedtuple
152+
>>> Student = namedtuple('Student', ['name', 'id', 'age']) # 定义了一个 Student 元组
153+
>>>
154+
>>> stu = Student('ethan', '001', 20)
155+
>>> stu.name
156+
'ethan'
157+
>>> stu.id
158+
'001'
159+
```
160+
161+
# deque
162+
163+
deque 是双端队列,允许我们在队列两端添加或删除元素。
164+
165+
```python
166+
>>> from collections import deque
167+
168+
>>> q = deque(['a', 'b', 'c', 'd'])
169+
>>> q.append('e') # 添加到尾部
170+
>>> q
171+
deque(['a', 'b', 'c', 'd', 'e'])
172+
>>> q.appendleft('o') # 添加到头部
173+
>>> q
174+
deque(['o', 'a', 'b', 'c', 'd', 'e'])
175+
>>> q.pop() # 从尾部弹出元素
176+
'e'
177+
>>> q
178+
deque(['o', 'a', 'b', 'c', 'd'])
179+
>>> q.popleft() # 从头部弹出元素
180+
'o'
181+
>>> q
182+
deque(['a', 'b', 'c', 'd'])
183+
>>> q.extend('ef') # 在尾部 extend 元素
184+
>>> q
185+
deque(['a', 'b', 'c', 'd', 'e', 'f'])
186+
>>> q.extendleft('uv') # 在头部 extend 元素,注意顺序
187+
>>> q
188+
deque(['v', 'u', 'a', 'b', 'c', 'd', 'e', 'f'])
189+
>>>
190+
>>> q.rotate(2) # 将尾部的两个元素移动到头部
191+
>>> q
192+
deque(['e', 'f', 'v', 'u', 'a', 'b', 'c', 'd'])
193+
>>> q.rotate(-2) # 将头部的两个元素移动到尾部
194+
>>> q
195+
deque(['v', 'u', 'a', 'b', 'c', 'd', 'e', 'f'])
196+
```
197+
198+
其中,`rotate` 方法用于旋转,如果旋转参数 n 大于 0,表示将队列右端的 n 个元素移动到左端,否则相反。
199+
200+
201+
# 参考资料
202+
203+
- [collections — High-performance container datatypes — Python 2.7.13 documentation](https://docs.python.org/2/library/collections.html#module-collections)
204+
205+

0 commit comments

Comments
 (0)