Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python - Create Counter() from mapping, non-integer values

Tags:

python

counter

Consider a basic counter initialized from a mapping:

dict_1 = {'a': 1, 'b': 2, 'c': 3}
count_1 = Counter(dict_1)
print count_1

>>> Counter({'c': 3, 'b': 2, 'a': 1})

Everything makes sense. But Counter also allows me to initialize from a dictionary that has non-integers as both keys and values. For example,

dict_2 = {'a': 'apple', 'b': 'banana', 'c': 'cheese'}
count_2 = Counter(dict_2)
print count_2

>>> Counter({'c': 'cheese', 'b': 'banana', 'a': 'apple'})

The code written above is Python 2.7, but I also tested it on Python 3.5 and got the same result. This seems to violate the most basic rule of the counter, where "elements are stored as dictionary keys and their counts are stored as dictionary values." Is counter supposed to allow values that aren't integers? Shouldn't it thrown an error or something? What explains this behavior?

like image 352
GHH Avatar asked Dec 03 '16 17:12

GHH


1 Answers

There are no restrictions on the values of a counter object and this is clearly stated in the documentation:

The Counter class itself is a dictionary subclass with no restrictions on its keys and values. The values are intended to be numbers representing counts, but you could store anything in the value field.

[Emphasis mine]

The behavior of some of the Counter methods is also described in a general case e.g.:

The most_common() method requires only that the values be orderable.

>>> count_2.most_common()
[('c', 'cheese'), ('b', 'banana'), ('a', 'apple')]
>>> count_2.most_common(2)
[('c', 'cheese'), ('b', 'banana')]

So one could easily run into problems in Python 3 if you have unorderable types as values in the counter object:

>>> count_2['d'] = 2
>>> count_2
Counter({'c': 'cheese', 'a': 'apple', 'b': 'banana', 'd': 2})
>>> count_2.most_common()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "c:\Python34\lib\collections\__init__.py", line 492, in most_common
    return sorted(self.items(), key=_itemgetter(1), reverse=True)
TypeError: unorderable types: str() < int()

Hence, you'll generally want to keep the values as the actual count of objects and use a vanilla dictionary when values are intended to be non numeric types or more strictly non integers.

like image 192
Moses Koledoye Avatar answered Oct 24 '22 03:10

Moses Koledoye