DEV Community

Cover image for Python's Collections Module: OrderedCounter
Kathan Vakharia
Kathan Vakharia

Posted on

Python's Collections Module: OrderedCounter

What are we trying to achieve?

If you recall from last post, here's the Method Resolution Order of Counter class:
imageThere's no way we can swap the priority order. One option is to be cheeky 😛 and make use of the __repr__ method of builtins.dict

Option1: Casting a Counter Object to dict

By casting the Counter to dict, print will use__repr__ method of dict which will make sure, order is maintained!

imageBut this doesn't draw the idea home, I mean what if a novice looks at this code? He has no idea why we are casting the Counter to dict.
So a better approach would be to create our own custom OrderedCounter class for clarity.

Option 2: Creating a custom OrderedCounter class

We can create a class that inherits from Counter and implement it's own version of __repr__ method,

The idea is still the same: cast the Counter to dict but this time by providing abstraction and thereby improving the readability of code.

class OrderedCounter(Counter):
    'Counter that remembers the order elements are first encountered'

    def __repr__(self):
                        # casting 'self' to dict will do the job
        return '%s(%r)' % (self.__class__.__name__, dict(self))

    def __reduce__(self):
        return self.__class__, (dict(self),)
Enter fullscreen mode Exit fullscreen mode

Here, the instantiation(creation) of OrderedCounter Object will be done by the __init__ method of Counter class. This means a object of type OrderedCounter contains the count of values in iterable passed a.k.a behaves like Counter.

The __reduce__ method implementaton is necessary for 'PICKLING' purpose which we will discuss in some other post.

OrderedCounter in action!

# creating Ordered Counters
ordered_c0 = OrderedCounter('kkkaaaajjjjkkaaakklll')
ordered_c1 = OrderedCounter(["oranges", "apples", "apples", "bananas",
                             "kiwis", "kiwis", "apples"])


print(ordered_c0, ordered_c1, sep='\n')

"""OUTPUT => Order Maintained 

{'k': 7, 'a': 7, 'j': 4, 'l': 3}
{'oranges': 1, 'apples': 3, 'bananas': 1, 'kiwis': 2}
"""
Enter fullscreen mode Exit fullscreen mode

There are some other ways too, but knowing these two ways are more than enough!

References:

https://stackoverflow.com/questions/35446015/creating-an-ordered-counter

Latest comments (0)