0

I want to add 2 functions in collections.Counter to add functionality to it for sorting and returning minimum n values. For this to work, I need to access the internal dictionary and I don't know how to use it. I checked the internal variables for the class created by using vars(Counter) and also the dunder and other function using dir(Counter). As the dictonary us returned after creating the class so the method and variable is in the constructor itself. So to see the functionality I used dir(Counter.__init__) but could not find something good to use, as only methods were there.

For example if I do counter = Counter(iterable), i need to access that self.counter variable Inside the class itself but I do not which variable that would be.

Below is the code I want to implement

from collections import Counter
import heapq
from operator import itemgetter


class CounterNew(Counter):
    '''
    Increase the functionality of collections.Counter() class
    '''
    def least_common(n:int)->list:
        '''
        Get the least common elements
        args:
            n: How many elements you want to have which have the lowest frequency
        out: list of tuples as [(key,frequency)]
        '''
        return heapq.nsmallest(n, counter.items(), key=lambda x:x[1])
    
    
    def sort_by_freq(self,reverse:bool=False)->dict:
        '''
        Sort the Dictonary by frequency counts
        args:
            reverse: Whether to sort the dictonary in increasing or decreasing order
        out: Sorted dictonary
        '''
        self.sorted = sorted(counter.items(), key=lambda x:x[1], reverse=reverse) # How can I sort the internal dictonary that is returned by class
        return self.sorted
Deshwal
  • 3,436
  • 4
  • 35
  • 94

1 Answers1

2

collections.Counter is a subclass of dict. So it doesn't contain a dictionary in an instance variable, the dictionary is the instance itself. So if you need to access the dictionary, just use self.

You do the same thing in the sort_by_freq method. Since you want it to return a dict, you need to call dict() to convert it back into a dictionary.

def least_common(self, n:int)->list:
    return heapq.nsmallest(n, self.items(), key=lambda x:x[1])

def sort_by_freq(self,reverse:bool=False)->dict:
    '''
    Sort the Dictonary by frequency counts
    args:
        reverse: Whether to sort the dictonary in increasing or decreasing order
    out: Sorted dictonary
    '''
    self.sorted = dict(sorted(self.items(), key=lambda x:x[1], reverse=reverse))
    return self.sorted
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • Oh! That's something new. First time hearing that you can access `self` itself like this. Thanks a lot. – Deshwal May 18 '21 at 05:33
  • And what is I want to store the sorted dict? I mean how can I do it? Sort the internal dictionary? – Deshwal May 18 '21 at 05:35
  • The method definition is missing the `self` argument. – ekhumoro May 18 '21 at 10:20
  • @ekhumoro Can you please explain it? Sorry I did not get it. I mean is there any code I need to change? – Deshwal May 18 '21 at 12:24
  • @Deshwal `def least_common(self, n:int)->list:`. – ekhumoro May 18 '21 at 12:51
  • @Deshwal All instance methods in a class need a `self` parameter. – Barmar May 18 '21 at 13:55
  • @Deshwal Don't you access `self` like this in most class methods? What makes this case different? – Barmar May 18 '21 at 13:56
  • I've updated the answer to show how to store the sorted dict in `self.sorted`. – Barmar May 18 '21 at 13:59
  • @Barmar No actually this is what I am saying. This is what I have done `self.sorted` but it'll create a new internal `dict` object which is sorted. I want to sort the existing `self`. Is there any method to do this so when I do `print(vocab)`, it prints the sorted vocab itself instead of doing `vocab.sorted` – Deshwal May 18 '21 at 18:18
  • Dictionaries don't support reordering themselves. So you'd have to override the entire internal implementation of the dictionary. – Barmar May 18 '21 at 18:20
  • Actually, I think you could empty the dictionary and then do `self.update(self.sorted)` – Barmar May 18 '21 at 18:22
  • `self.clear()` then `self.update(self.sorted)` – Barmar May 18 '21 at 18:23
  • The `Counter` class already has all this behaviour built-in. sorted by freq asc: `x.most_common()`; sorted by freq desc: `x.most_common()[::-1]`; least common N: `x.most_common()[:-N-1:-1]`. – ekhumoro May 19 '21 at 10:53