Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I initialize a Counter from a list of key/initial counts pairs?

If I have a sequence of (key, value) pairs, I can quickly initialize a dictionary like this:

>>> data = [ ('a', 1), ('b', 2) ]
>>> dict(data) 
{'a': 1, 'b': 2} 

I would like to do the same with a Counter dictionary; but how? Both the constructor and the update() method treat the ordered pairs as keys, not key-value pairs:

>>> from collections import Counter
>>> Counter(data)
Counter({('a', 1): 1, ('b', 2): 1})

The best I could manage was to use a temporary dictionary, which is ugly and needlessly circuitous:

>>> Counter(dict(data))
Counter({'b': 2, 'a': 1})

Is there a proper way to directly initialize a Counter from a list of (key, count) pairs? My use case involves reading lots of saved counts from files (with unique keys).

like image 666
alexis Avatar asked May 06 '17 20:05

alexis


People also ask

How do you initialize a counter?

Initializing. Counter supports three forms of initialization. Its constructor can be called with a sequence of items, a dictionary containing keys and counts, or using keyword arguments mapping string names to counts. To create an empty counter, pass the counter with no argument and populate it via the update method.

How do I turn a list into a counter in Python?

In Python, you can count the total number of elements in a list or tuple with the built-in function len() and the number of occurrences of an element with the count() method.

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.

What is collections counter () in Python?

A Counter is a dict subclass for counting hashable objects. It is a collection where elements are stored as dictionary keys and their counts are stored as dictionary values. Counts are allowed to be any integer value including zero or negative counts.


2 Answers

I would just do a loop:

for obj, cnt in [ ('a', 1), ('b', 2) ]:
    counter[obj] = cnt

You could also just call the parent dict.update method:

>>> from collections import Counter
>>> data = [ ('a', 1), ('b', 2) ]
>>> c = Counter()
>>> dict.update(c, data)
>>> c
Counter({'b': 2, 'a': 1})

Lastly, there isn't anything wrong with your original solution:

Counter(dict(list_of_pairs))

The expensive part of creating dictionaries or counters is hashing all of the keys and doing periodic resizes. Once the dictionary is made, converting it to a Counter is very cheap about as fast as a dict.copy(). The hash values are reused and the final Counter hash table is pre-sized (no need for resizing).

like image 149
Raymond Hettinger Avatar answered Sep 25 '22 03:09

Raymond Hettinger


From docs:

Elements are counted from an iterable or initialized from another mapping (or counter)

So it's a No, you need to convert it to mapping and then initialize Counter. And Yes when you initialized with dict it was the right move.

UPDATE

I agree that @RaymondHettinger code looks good, and actually it's faster

from collections import Counter
from random import choice
from string import ascii_letters
a=[(choice(ascii_letters), i) for i in range(100)]

Tested with Python 3.6.1 and IPython 6

Initialization with dict:

%%timeit
c1=Counter(dict(a))

Output

12.1 µs ± 342 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Update with dict.update()

%%timeit    
c2=Counter()
dict.update(c2, a)

Output:

7.21 µs ± 236 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
like image 39
vishes_shell Avatar answered Sep 27 '22 03:09

vishes_shell