How to sort Counter by value? - python
Solution 1
Use the Counter.most_common()
method, it'll sort the items for you:
>>> from collections import Counter
>>> x = Counter({'a':5, 'b':3, 'c':7})
>>> x.most_common()
[('c', 7), ('a', 5), ('b', 3)]
It'll do so in the most efficient manner possible; if you ask for a Top N instead of all values, a heapq
is used instead of a straight sort:
>>> x.most_common(1)
[('c', 7)]
Outside of counters, sorting can always be adjusted based on a key
function; .sort()
and sorted()
both take callable that lets you specify a value on which to sort the input sequence; sorted(x, key=x.get, reverse=True)
would give you the same sorting as x.most_common()
, but only return the keys, for example:
>>> sorted(x, key=x.get, reverse=True)
['c', 'a', 'b']
or you can sort on only the value given (key, value)
pairs:
>>> sorted(x.items(), key=lambda pair: pair[1], reverse=True)
[('c', 7), ('a', 5), ('b', 3)]
See the Python sorting howto for more information.
Solution 2
A rather nice addition to @MartijnPieters answer is to get back a dictionary sorted by occurrence since Collections.most_common
only returns a tuple. I often couple this with a json output for handy log files:
from collections import Counter, OrderedDict
x = Counter({'a':5, 'b':3, 'c':7})
y = OrderedDict(x.most_common())
With the output:
OrderedDict([('c', 7), ('a', 5), ('b', 3)])
{
"c": 7,
"a": 5,
"b": 3
}
Solution 3
Yes:
>>> from collections import Counter
>>> x = Counter({'a':5, 'b':3, 'c':7})
Using the sorted keyword key and a lambda function:
>>> 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)]
This works for all dictionaries. However Counter
has a special function which already gives you the sorted items (from most frequent, to least frequent). It's called 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)]
You can also specify how many items you want to see:
>>> x.most_common(2) # specify number you want
[('c', 7), ('a', 5)]
Solution 4
More general sorted, where the key
keyword defines the sorting method, minus before numerical type indicates descending:
>>> x = Counter({'a':5, 'b':3, 'c':7})
>>> sorted(x.items(), key=lambda k: -k[1]) # Ascending
[('c', 7), ('a', 5), ('b', 3)]
Related videos on Youtube
Comments
-
alvas almost 2 years
Other than doing list comprehensions of reversed list comprehension, is there a pythonic way to sort Counter by value? If so, it is faster than this:
>>> 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)
-
Steinar Lima over 10 yearsAnother way to reverse sort is to set the key function to
lamda i: -i[1]
-
Alex Seam over 5 yearsThe
key
keyword defines the sorting method, minus before numerical type indicate descending -
Walter Tross over 3 yearsStarting from Python 3.7 (3.6 for CPython) there is no need for
OrderedDict
any more, becausedict
now keeps the insertion order. So it's simplyy = dict(x.most_common())
-
questionto42standswithUkraine over 2 yearsI had forgotten the
.items()
which then gave meTypeError: bad operand type for unary -: 'str'
. It is just that you need theitems()
to make it read as a pair so thatk[1]
is found as the second item of each pair which can be reverse sorted with-k[1]
because it is a number. You would not be able to do-k[0]
sincek[0]
is a string. -
Flimm about 2 years@WalterTross Just to be clear, even in Python 3.7+,
OrderedDict
offers functionality thatdict
doesn't, especially regarding comparisons. For example,OrderedDict([('a', 1), ('b', 2)]) == OrderedDict([('b', 2), ('a', 1)])
evaluates to False, whereas{'a': 1, 'b': 2} == {'b': 2, 'a': 1}
evaluates to True.