How to sort Counter by value? - python

191,613

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)]
Share:
191,613

Related videos on Youtube

alvas
Author by

alvas

食飽未?

Updated on July 08, 2022

Comments

  • alvas
    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
    Steinar Lima over 10 years
    Another way to reverse sort is to set the key function to lamda i: -i[1]
  • Alex Seam
    Alex Seam over 5 years
    The key keyword defines the sorting method, minus before numerical type indicate descending
  • Walter Tross
    Walter Tross over 3 years
    Starting from Python 3.7 (3.6 for CPython) there is no need for OrderedDict any more, because dict now keeps the insertion order. So it's simply y = dict(x.most_common())
  • questionto42standswithUkraine
    questionto42standswithUkraine over 2 years
    I had forgotten the .items() which then gave me TypeError: bad operand type for unary -: 'str'. It is just that you need the items() to make it read as a pair so that k[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] since k[0] is a string.
  • Flimm
    Flimm about 2 years
    @WalterTross Just to be clear, even in Python 3.7+, OrderedDict offers functionality that dict 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.