0%

Counter的most_common()源码阅读笔记

这个方法可以传一个可选参数 n, 代表获取数量最多的前 n 个元素。如果不传参数,则返回所有结果。

反回的结果是一个列表,里边的元素是一个元组,元组第0位是被计数的具体元素,元组第1位是出现的次数。如:[('a', 5), ('b', 4), ('c', 3)],当多个元素计数值相同时,按照字母序排列。

下边是 most_common 的源码:

1
2
3
4
def most_common(self, n=None):
if n is None:
return sorted(self.iteritems(), key=_itemgetter(1), reverse=True)
return _heapq.nlargest(n, self.iteritems(), key=_itemgetter(1))

先来看n是None的情况,因为Counter类继承自dict,所以 self.iteritems 得到的是键值对元组的列表,用 sorted对这个列表进行排序,因为是要按照元组的第1位的数字从大到小的顺序来排序,所以key应该是元组的第1位。代码中用 _itemgetter(1)来取出元组的第1位,_itemgetteroperator 模块里的 itemgetter 类,这个类重写了 __call__ 方法,所以这个类的实例可以当做函数来调用。 具体用法如下:

1
2
After f = itemgetter(2), the call f(r) returns r[2].
After g = itemgetter(2, 5, 3), the call g(r) returns (r[2], r[5], r[3])

现在 key=itemgetter(1), 即 key(r) 就是 r[1] 这样就可以取到我们想要的那个值了,如果换作之前,我可能会重新定义一个函数,然后赋值给key,最多写一个lambda表达式: lambda x:x[1]赋值给key,这些都是重造轮子的例子。。。不好不好。。。

此时我们实际要进行的是整数之间的比较,就不用再给 sortedcmp 参数赋值了,因为我们要得到一个从大到小排列的结果,所以最后 reverse=True

如果 n 不为 None ,调用了 heapq(最上边导入时将heapq as 重命名成了 _heapq) 模块中的 nlargest 函数,这个函数的实现有些略微复杂,等以后有时间再去看,直接看下函数的介绍:

1
2
Find the n largest elements in a dataset.
Equivalent to: sorted(iterable, key=key, reverse=True)[:n]

这个函数的调用结果和用 sorted 排序后再取出前n个结果等价。

也就是 sorted(self.iteritems(), key=_itemgetter(1), reverse=True)[:n]

下一篇写Counter的elements()方法