1.Counters作为一个容器,可以跟踪相同的值增加了多少次。这个类可以用来实现其他语言中常用包(bag)或多集合(multiset)数据结构来实现的算法。
初始化
Counter支持3中形式的初始化。调用Counter的构造函数时可以提供一个元素序列或者一个包含键和计数的字典,还可以使用关键字参数将字符串名映射到计数。
import collections
print(collections.Counter(['a','b','c','a','b','c']))
print(collections.Counter({'a':2,'b':3,'c':1})) print(collections.Counter(a=2,b=3,c=1))
如果不提供任何参数,可以构造一个空Counter,然后通过update()方法填充。
import collections c = collections.Counter() print('Interval :',c) c.update('abcdaab') print('Sequence', c) c.update({'a':1,'d':5})
计数值将根据新数据增加,替换数据不会改变计数。
Interval : Counter() Sequence Counter({'a': 3, 'b': 2, 'c': 1, 'd': 1}) Dict: Counter({'d': 6, 'a': 4, 'b': 2, 'c': 1})
访问计数
一旦填充了Counter,可以使用字典API获取他的值。
c = collections.Counter('abcdaab') for letter in 'abcde': print('%s : %d' % (letter, c[letter]))
对未知的元素,Counter不会产生KeyError。如果在输入中没有找到某个值(如此例中的e),其计数为0。
a : 3 b : 2 c : 1 d : 1 e : 0
elements()方法返回一个迭代器,将生成Counter知道的所有元素。
c = collections.Counter('extremely') c['z']= 0 print(c) print(list(c.elements()))
不能保证元素的顺序不变,另外计数小于或等于0的元素不包含在内。
Counter({'e': 3, 'x': 1, 't': 1, 'r': 1, 'm': 1, 'l': 1, 'y': 1, 'z': 0}) ['e', 'e', 'e', 'x', 't', 'r', 'm', 'l', 'y']
使用most_common()可以生成一个序列,其中包含n个最常遇到的输入值及其相应计数。
c = collections.Counter() with open('words.text', 'rt') as f: for line in f: c.update(line.rstrip().lower()) print('Most common:') for letter,count in c.most_common(3): print('%s : %7d' % (letter, count))
这个例子要统计系统的所有单词出现的字母,来生成一个频度分布,然后打印3个最常见的字母。如果不向most_common()提供参数,会生成成所有元素构成一个列表。按照频度排列。
Most common: o : 15 j : 12 d : 10
算数操作
Counter实例支持算数和集合操作来完成结果的聚集。
c1 = collections.Counter(['a','b','c','a','b','b']) c2 = collections.Counter('alphabet') print('C1:',c1) print('C2:',c2) print('\nCombined counts:') print(c1 + c2) print('\nSubtraction:') print(c1 - c2) print('\nIntersection (taking positive minimums):') print(c1 & c2) print('\nUnion (taking maximums):') print(c1 | c2)
每次通过一个操作生成一个新的Counter时,计数为0或负数的元素都会被删除。在c1和c2中a的计数相同,所以减法操作后他的计数为0.
C1: Counter({'b': 3, 'a': 2, 'c': 1}) C2: Counter({'a': 2, 'l': 1, 'p': 1, 'h': 1, 'b': 1, 'e': 1, 't': 1}) Combined counts: Counter({'a': 4, 'b': 4, 'c': 1, 'l': 1, 'p': 1, 'h': 1, 'e': 1, 't': 1}) Subtraction: Counter({'b': 2, 'c': 1}) Intersection (taking positive minimums): Counter({'a': 2, 'b': 1}) Union (taking maximums): Counter({'b': 3, 'a': 2, 'c': 1, 'l': 1, 'p': 1, 'h': 1, 'e': 1, 't': 1})
2.defaultdict。标准字典包括一个方法setdefault()来获取一个值,如果这个值不存在则建立一个默认值。与之相反,defaultdict初始化容器是会让调用者提前指定默认值。
def default_factory(): return 'default value' d = collections.defaultdict(default_factory,foo = 'bar') print('d', d) print('foo =>', d['foo']) print('bar =>', d['bar'])
只要所有键都有相同的默认值并无不妥。就可以使用这个方法。如果默认值是一种用于聚集或累加值的类型,如:list,set或者甚至是int,这个方法尤其有用。
d defaultdict(<function default_factory at 0x00000000024F9DC8>, {'foo': 'bar'}) foo => bar bar => default value
3.deque。(双端队列)支持从任意一段增加和删除元素。更为常用的两种结构,即栈和队列,就是双端队列的退化形式,其输入和输出限制在一段。
d = collections.deque('abcdefg') print('Deque:', d) print('Length:', len(d)) print('Left end:', d[0]) print('Right end:', d[-1]) d.remove('c') print('remove(c):', d)
由于deque是一种序列容器,因此同样支持list的一些操作,如用__getitem__()检查内容,确定长度,以及通过匹配小时从序列中间删除元素。
Deque: deque(['a', 'b', 'c', 'd', 'e', 'f', 'g']) Length: 7 Left end: a Right end: g remove(c): deque(['a', 'b', 'd', 'e', 'f', 'g'])
填充
deque可以从任意一端填充,可以左端填充,和右端填充。
#Add to the right d1 = collections.deque() d1.extend('abcdefg') print('extend:', d1) d1.append('h') print('append:', d1) #Add to the left d2 = collections.deque() d2.extendleft(range(6)) print('extendleft:', d2) d2.appendleft(6) print('appendleft:', d2)
extendleft()函数迭代处理其输入,对各个元素完成与appendleft()同样的处理。最终结果是deque将包含逆序的输入序列。
extend: deque(['a', 'b', 'c', 'd', 'e', 'f', 'g']) append: deque(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']) extendleft: deque([5, 4, 3, 2, 1, 0]) appendleft: deque([6, 5, 4, 3, 2, 1, 0])
利用
类似地,可以从两端或任意一端利用deque的元素,这取决于所应用的算法。
print('From the right:') d = collections.deque('abcdefg') while True: try: print(d.pop()) except IndexError: break print('\nFrom the left:') d = collections.deque(range(6)) while True: try: print(d.popleft()) except IndexError: break
使用pop(0可以从deque的右端删除一个元素。使用popleft()可以从deque的左端删除一个元素。
From the right: g f e d c b a From the left: 0 1 2 3 4 5
由于双端队列是线程安全的,所以甚至可以在不同线程中同时从两端利用队列的内容。