I have a list of counters in python:
[Counter({12.011: 30.0, 15.999: 2.0}),
Counter({12.011: 12.0, 15.999: 2.0}),... Counter({12.011: 40.0,
15.999: 5.0, 79.904: 5.0})]
How do I find the count of each Counter element. Counter gives me an error of unhashable type. Another way I thought is to iterate through the list in a nested for-loop, checking if each counter is equal to any other counter in the list and increment a dictionary accordingly. Is there a better solution?
sort() and == operator. The list. sort() method sorts the two lists and the == operator compares the two lists item by item which means they have equal data items at equal positions. This checks if the list contains equal data item values but it does not take into account the order of elements in the list.
Accessing Elements in Python Counter To get the list of elements in the counter we can use the elements() method. It returns an iterator object for the values in the Counter.
Counter is a subclass of dict that's specially designed for counting hashable objects in Python. It's a dictionary that stores objects as keys and counts as values. To count with Counter , you typically provide a sequence or iterable of hashable objects as an argument to the class's constructor.
In Python <= 3.6 your best bet is probably comparing every Counter
to every other Counter
.
In Python >= 3.7 there is a better way. Because Counter
is a subclass of dict
, and dict
now keep their order, it is possible to use the string representation of each Counter
object as its hash.
This is a bit hacky but it works:
from collections import Counter
li = [Counter({'a': 1, 'b': 2, 'c': 3}),
Counter({'a': 1, 'b': 2, 'c': 4}),
Counter({'a': 1, 'b': 3, 'c': 3}),
Counter({'a': 1, 'b': 2, 'c': 3})]
Counter.__hash__ = lambda counter: hash(str(counter))
print(Counter(li))
# Counter({Counter({'c': 3, 'b': 2, 'a': 1}): 2,
# Counter({'c': 4, 'b': 2, 'a': 1}): 1,
# Counter({'b': 3, 'c': 3, 'a': 1}): 1})
You could convert each Counter into a frozenset of key, value (items) tuples and then use this as elements to pass to a Counter (as frozenset are hashable), for example like this:
import random
from collections import Counter
random.seed(42)
counts = [Counter([random.randint(0, 2) for _ in range(10)]) for _ in range(10)]
uniques = {frozenset(e.items()): e for e in counts}
counters_count = Counter(map(lambda e : frozenset(e.items()), counts))
for key, count in counters_count.items():
print uniques[key], count
Output
Counter({0: 7, 1: 2, 2: 1}) 1
Counter({1: 4, 2: 4, 0: 2}) 1
Counter({0: 4, 1: 4, 2: 2}) 2
Counter({0: 4, 1: 3, 2: 3}) 1
Counter({0: 5, 2: 3, 1: 2}) 1
Counter({1: 5, 2: 5}) 1
Counter({0: 5, 1: 4, 2: 1}) 1
Counter({0: 4, 2: 4, 1: 2}) 1
Counter({2: 4, 0: 3, 1: 3}) 1
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With