Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparing list of Counters in Python

Tags:

python

counter

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?

like image 807
user2657817 Avatar asked Dec 09 '18 17:12

user2657817


People also ask

How do you compare items in a list in python?

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.

How do you show a Counter list in python?

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.

What does Counter () do in python?

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.


2 Answers

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})
like image 189
DeepSpace Avatar answered Oct 24 '22 13:10

DeepSpace


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
like image 20
Dani Mesejo Avatar answered Oct 24 '22 13:10

Dani Mesejo