Hacer que Counter considere dos objetos de la misma clase iguales

I'm using collections.Counter. It's great so far, except that I'd like it to count objects of the same class as the same. How can I do this? I tried overriding the hachís() method on the class so that all instances would hash the same. Right now, if I do Counter([Type1(), Type1(), Type2(), Type2()]) volverá {<Type1 object at...>:1,<Type1 object at...>:1,<Type2 object at...>:1,<Type2 object at...>:1} I would prefer it to return something like {"Type1":2, "Type2":2} instead. Is this possible? I was poking around the docs and couldn't figure out how to make it work.

I should add that the classes I'm using are essentially wrappers for constant values. It's just more convenient to wrap them in a class. Under no circumstances will one Type1 object ever differ from another Type1 object.

preguntado el 09 de septiembre de 13 a las 23:09

3 Respuestas

¿Qué tal esto?

Counter(type(x) for x in [Type1(), Type1(), Type2(), Type2()])

Así es como lo usaría:

>>> type_counter = Counter(type(x) for x in [Type1(), Type1(), Type2(), Type2()])
>>> type_counter
Counter({<class '__main__.Type2'>: 2, <class '__main__.Type1'>: 2})
>>> type_counter[Type1]
2
>>> type_counter[type(Type2())]
2

Respondido el 09 de Septiembre de 13 a las 23:09

This is the best way. Classes can be used as dictionary keys! - un poco

After having read your question again, I'm adding a different approach which might be more suitable to your needs.

A Counter is a dictionary, and dictionaries in Python use the __hash__ método y el __eq__ method to compare objects. So you need to define these two methods if you want objects which always compare equal and can be used as dictionary keys.

# (Python 3)
class Type1:
    def __eq__(self, other):
        if isinstance(other, Type1):
            return True
        return super().__eq__(other)

    def __hash__(self):
        return 1329916036    # anything constant

If you do the same for Type2, you can count instances in a Counter Me gusta esto:

>>> mycounter = Counter([Type1(), Type1(), Type2(), Type2()])
>>> mycounter
Counter({<__main__.Type1 object at ...>: 2, <__main__.Type2 object at ...>: 2})
>>> mycounter[Type1()]
2

Respondido el 10 de Septiembre de 13 a las 00:09

Ah, eq, that's what I was missing. Thank you. I actually think the approach you suggested works better for my particular situation, though this is what I was asking for! - afkbowflexina

If you want to group them by class name, you can use the __name__ atributo:

Counter(i.__name__ for i in (Type1(), Type2(), Type1()))

o:

from operator import attrgetter

Counter(map(attrgetter('__name__'), (Type1(), Type2(), Type1())))

Respondido el 10 de Septiembre de 13 a las 00:09

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.