Using Python's Counter Class
For more information on concepts covered in this lesson, you can check out Reverse Strings in Python: reversed(), Slicing, and More.
00:00
In the previous lesson, I showed you a counting problem and tooled a solution by hand. In this lesson, I’ll show you how to use Python’s Counter
class to make this simpler.
00:11
The Counter
class is a member of the collections
library, and like several of the other classes within that library, it is based on a dictionary.
00:19 In this case, the keys are the instances of things being counted while the corresponding values are the count of those things. You came here to code. Let’s dive into the REPL.
00:39
Think back to the Mississippi letter-counting problem in the previous lesson. Here is a much shorter version. Yep. That’s it. Creating a Counter
object results in counting whatever iterable is passed in. A string, in an iterable context, gives each letter inside of the string, so passing a string to Counter
counts each of the unique letters. Counters can also take lists.
01:09
Passing in the list, in this case, the list is turning the string into the interable of letters, and passing the list into Counter
ends up in the same result.
01:18 You can also pass in dictionaries.
01:26
In this case, the key-value pairs indicate objects being counted and their corresponding counts. Essentially, the data structure our results got stored in back when a variety of cats were in danger. All right, I’ll stop with the cat jokes, I promise. You can also pass in named arguments to Counter
.
01:48 Each named argument is treated as a string with the corresponding value being the count. Alternatively, you can give it a set. Remember that sets are also constructed based on iteration, but they can only hold one instance of each thing in the iteration.
02:08
Creating a set for "mississippi"
iterates on the letters, keeping only the unique values. Create a counter based on the set results in a count of 1
for each of the letters.
02:19 Counters are just dictionaries. You can use any hashable item as a key and store any value. The only caveat is that if the value is not an integer, you won’t be able to increment that count later.
02:33
So although it won’t stop you from storing anything, if you want to take advantage of some of the key additional features of Counter
, you really only want to store integers.
02:42 Let me show you another example using arguments.
02:52
Here, I’m storing integers, and one of them is negative. What does -15
tomatoes mean? Well, maybe you owe your neighbor that many, and this counter is tracking what’s in your fridge.
03:04
You know how a second ago, I mentioned you can increment the counter later? Well it’s later. A little deja vu, and one Mississippi. And now with the Counter
instance, I can change values by calling the .update()
method.
03:26
Like the initializer, .update()
takes any iterable. Iterating on "ohio"
adds two 'o'
s, an 'h'
, and an 'i'
to the count.
03:36
You can see the difference here. You can also call .update()
with a dictionary.
03:48
That’s a lot of 'i'
s. Notice updating with -5
'h'
s leaves -4
'h'
s in the counter. You’re probably starting to see the pattern here. You can update with arguments.
04:04
That’s five more 's'
s and five more 'p'
s. As Counter
is just a special type of dictionary, you can access a key with a subscript, which means you can loop over your counter.
04:26
Likewise, counters have a .keys()
method so that you can get at the keys in your counter …
04:44
and a .values()
method …
05:11
All your inherited dictionary goodness. One behavior of counters that’s a little different than dictionaries is when you ask for a key that isn’t there. Instead of getting a KeyError
, you get the count. There are zero 'a'
s in mississippi
. Well, mississippi
plus a bunch of other things I did, but there’s no 'a'
s there.
05:34 Note that this is case sensitive. Nothing I’ve typed has a capital letter in it. So asking for one is going to return zero. Another service the counter offers is information on how common the elements in the container are. Consider a counter tracking how many pieces of fruit got sold.
06:04
The .most_common()
method returns a list of tuples. The tuples are the key-value pairs in the counter, and the list is in order of frequency: apples are most common, tomatoes the least.
06:19
You can pass an argument to .most_common()
to limit how many items come back. This is just the most popular type of fruit. And that is the two most popular.
06:36
Passing in None
is the same as no argument. You get back the whole list. Passing in a number bigger than the number of items in the container returns the whole list as well. What about the least common items?
06:52 Well, there’s no method for that, but you can get at it with a bit of work.
07:02
I’ll start by capturing the most common. Remember that this returns a list. And then I call the .reverse()
method on that list. Voila! You’ve got it all backwards, as intended.
07:19
There’s more than one way to—oh wait, I made a promise. Anyhow, you can also call the built-in function reversed()
. This gives you a list_reverseiterator
, which you can put in a for
loop or do whatever else you normally do with an iterator. I’m just going to stick it in the list so you can see the results.
07:47
One last way to accomplish the same thing. This is slightly harder to read, but a fairly common shortcut. It’s called the negative slice. This is a trick that works with the slicing operator ([::-1]
) to create a reversed list in place. See the description below for an article with more details on this.
08:11 Now you’ve seen how to use the class. Next up, I’ll show you some practical applications.
Become a Member to join the conversation.