Pythonic way to iterate over a collections.Counter() instance in descending order?

CollectionsIterationPython 2.7Python

Collections Problem Overview


In Python 2.7, I want to iterate over a collections.Counter instance in descending count order.

>>> import collections
>>> c = collections.Counter()
>>> c['a'] = 1
>>> c['b'] = 999
>>> c
Counter({'b': 999, 'a': 1})
>>> for x in c:
        print x
a
b

In the example above, it appears that the elements are iterated in the order they were added to the Counter instance.

I'd like to iterate over the list from highest to lowest. I see that the string representation of Counter does this, just wondering if there's a recommended way to do it.

Collections Solutions


Solution 1 - Collections

You can iterate over c.most_common() to get the items in the desired order. See also the documentation of Counter.most_common().

Example:

>>> c = collections.Counter(a=1, b=999)
>>> c.most_common()
[('b', 999), ('a', 1)]

Solution 2 - Collections

Here is the example to iterate the Counter in Python collections:

>>>def counterIterator(): 
...  import collections
...  counter = collections.Counter()
...  counter.update(('u1','u1'))
...  counter.update(('u2','u2'))
...  counter.update(('u2','u1'))
...  for ele in counter:
...    print(ele,counter[ele])
>>>counterIterator()
u1 3
u2 3
 

Solution 3 - Collections

Your problem was solved for just returning descending order but here is how to do it generically. In case someone else comes here from Google here is how I had to solve it. Basically what you have above returns the keys for the dictionary inside collections.Counter(). To get the values you just need to pass the key back to the dictionary like so:

for x in c:
    key = x
    value = c[key]

I had a more specific problem where I had word counts and wanted to filter out the low frequency ones. The trick here is to make a copy of the collections.Counter() or you will get "RuntimeError: dictionary changed size during iteration" when you try to remove them from the dictionary.

for word in words.copy():
    # remove small instance words
    if words[word] <= 3:
        del words[word]

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionInactivistView Question on Stackoverflow
Solution 1 - CollectionsSven MarnachView Answer on Stackoverflow
Solution 2 - CollectionsChandraView Answer on Stackoverflow
Solution 3 - Collectionsdreyco676View Answer on Stackoverflow