如何按值对计数器进行排序?- Python

223

除了使用反向列表推导式生成倒序列表外,是否有一种Pythonic的方法可以按值对Counter进行排序?如果是这样,它会比下面的代码更快:


除了使用反向列表推导式生成倒序列表外,是否有一种Pythonic的方法可以按值对Counter进行排序?如果是这样,它会比下面的代码更快:
>>> from collections import Counter
>>> x = Counter({'a':5, 'b':3, 'c':7})
>>> sorted(x)
['a', 'b', 'c']
>>> sorted(x.items())
[('a', 5), ('b', 3), ('c', 7)]
>>> [(l,k) for k,l in sorted([(j,i) for i,j in x.items()])]
[('b', 3), ('a', 5), ('c', 7)]
>>> [(l,k) for k,l in sorted([(j,i) for i,j in x.items()], reverse=True)]
[('c', 7), ('a', 5), ('b', 3)
4个回答

410

使用Counter.most_common()方法,它会为您自动排序

>>> from collections import Counter
>>> x = Counter({'a':5, 'b':3, 'c':7})
>>> x.most_common()
[('c', 7), ('a', 5), ('b', 3)]

它将以最高效的方式执行;如果您要求返回前N个而不是所有值,则使用heapq而不是直接排序:

>>> x.most_common(1)
[('c', 7)]

除了计数器以外,排序可以根据 key 函数进行调整;.sort()sorted() 都接受可调用对象,让你可以指定一个值来对输入序列进行排序;例如sorted(x, key=x.get, reverse=True) 将会给你与 x.most_common() 相同的排序,但只返回键,例如:

>>> sorted(x, key=x.get, reverse=True)
['c', 'a', 'b']

或者您可以仅按照给定的 (key, value) 对值进行排序:

>>> sorted(x.items(), key=lambda pair: pair[1], reverse=True)
[('c', 7), ('a', 5), ('b', 3)]

查看Python排序指南获取更多信息。


54

对于@MartijnPieters答案的一个相当不错的补充是获得按出现次数排序的字典,因为Collections.most_common只返回一个元组。我经常将其与json输出配对以便于编写方便的日志文件:

from collections import Counter, OrderedDict

x = Counter({'a':5, 'b':3, 'c':7})
y = OrderedDict(x.most_common())

输出结果为:

OrderedDict([('c', 7), ('a', 5), ('b', 3)])
{
  "c": 7, 
  "a": 5, 
  "b": 3
}

17
从Python 3.7开始(对于CPython是3.6),不再需要使用OrderedDict,因为现在的dict保留了插入顺序。所以直接使用y = dict(x.most_common())即可。 - Walter Tross
1
@WalterTross 只是为了明确,即使在Python 3.7+中,OrderedDict也提供了dict没有的功能,特别是关于比较方面的功能。例如,OrderedDict([('a', 1), ('b', 2)]) == OrderedDict([('b', 2), ('a', 1)])的结果为False,而{'a': 1, 'b': 2} == {'b': 2, 'a': 1}的结果为True。 - Flimm
OrderedDict在这里与普通字典相比没有任何更有用的地方。包括==检查。在这里,非有序字典做了正确的事情。插入顺序是所需的。有时候,您希望顺序改变比较结果。我认为您回复的评论并没有建议OrderedDict在任何情况下都不需要,只是在这里不需要,而且确实不需要。顺便说一句,尽管JSON规范中没有规定,但它实际上是按插入顺序排序的。 - Benjamin Atkin

24

是的:

>>> from collections import Counter
>>> x = Counter({'a':5, 'b':3, 'c':7})

使用排序关键字key和lambda函数:

>>> sorted(x.items(), key=lambda i: i[1])
[('b', 3), ('a', 5), ('c', 7)]
>>> sorted(x.items(), key=lambda i: i[1], reverse=True)
[('c', 7), ('a', 5), ('b', 3)]

这适用于所有字典。但是Counter有一个特殊的函数,它已经为您提供了排序后的项目(从最常见到最不常见)。它被称为most_common()

>>> x.most_common()
[('c', 7), ('a', 5), ('b', 3)]
>>> list(reversed(x.most_common()))  # in order of least to most
[('b', 3), ('a', 5), ('c', 7)]

您还可以指定要显示多少项:

>>> x.most_common(2)  # specify number you want
[('c', 7), ('a', 5)]

另一种反向排序的方法是将键函数设置为 lamda i: -i[1] - Steinar Lima
我忘了使用.items(),导致出现TypeError: bad operand type for unary -: 'str'错误。需要使用items()将它读作一对,这样可以通过-k[1]来查找每对的第二个项目并进行反向排序,因为这是一个数字。无法使用-k[0],因为k[0]是一个字符串。 - questionto42

10

更一般的排序,其中key关键字定义了排序方法,数字类型前的减号表示降序:

>>> x = Counter({'a':5, 'b':3, 'c':7})
>>> sorted(x.items(), key=lambda k: -k[1])  # Ascending
[('c', 7), ('a', 5), ('b', 3)]

2
key 关键字定义了排序方法,数字类型前的减号表示降序。 - Alex Seam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接