Mapping objects in python.Counter collections

I also have an instance of collection.Counter classes, I also have some objects like:

p1 = Person(name='John')
p2 = Person(name='John')
p3 = Person(name='Jane')

      

I want to store the counts for these person objects in a counter instance, taking into account that objects with the same name must increment the counter of the same person, so if I have a list with all the objects:

people = [p1, p2, p3]

      

and I will write my counter:

c = Counter(people)

      

I want to get the following:

c[p1] #prints 2
c[p2] #prints 2
c[p3] #prints 1

      

My first attempt was to implement a new __eq__

method for person objects

def __eq__(self, other):
  return self.name == other.name

      

I thought it might work because counter objects seem to increment for keys based on key object equality, like so:

c = Counter(['A', 'A', 'B'])
c['A'] #prints 2
c['B'] #prints 1

      

Another attempt could be inherited from Counter and override the base method that Counter uses to measure equality between objects, I'm not sure, but I think Counter uses a method for that __contains__

.

My question is, is there a way to get this behavior without using inheritance, and if not, what might be the best way to do it?

+3


source to share


2 answers


You also need to implement __hash__

:

class Person(object):
    def __init__(self, name=None, address=None):
        self.name = name
        self.address = address

    def __eq__(self, other):
        return self.name == other.name and self.address == other.address

    def __hash__(self):
        return hash((self.name, self.address))

      



Your code now works:

>>> Counter(people)
Counter({<__main__.Person object at 0x24a7590>: 2, <__main__.Person object at 0x24a75d0>: 1})

      

+7


source


If your objects are as simple as in your example use collections.namedtuple



from collections import Counter, namedtuple
Person = namedtuple('Person','name')

n1 = Person(name='John')
n2 = Person(name='John')
n3 = Person(name='Jane')
Counter((n1,n2,n3))
# Counter({Person(name='John'): 2, Person(name='Jane'): 1})

      

+2


source







All Articles