More handy tools

INPUT · Slides

Count how many of each there are

01 / 07

The shape you used to write for counting

Say you want to know how many times each colour came up. Think back to how Chapter 2 did it.

You make an empty dictionary, run a for over the values, and put a 1 in if the key is not there yet, or add 1 if it is. These six lines should look familiar.

They run, and they read well enough. But writing the same six lines every time you need something as ordinary as counting is a chore.

words = ["red", "blue", "red", "yellow", "red", "blue"]counts = {}for w in words:    if w in counts:        counts[w] += 1    else:        counts[w] = 1print(counts)

Result

{'red': 3, 'blue': 2, 'yellow': 1}

02 / 07

Just hand it to Counter

Those six lines come down to this. You use Counter, which lives in a standard library module called collections.

Bring the name in with from collections import Counter and pass it whatever you want counted. No for, no if.

Print it and it comes out as Counter({...}). What is inside is all but identical to a dictionary.

from collections import Counterwords = ["red", "blue", "red", "yellow", "red", "blue"]print(Counter(words))

Result

Counter({'red': 3, 'blue': 2, 'yellow': 1})

03 / 07

You can look it up like a dictionary

Counter is a kind of dictionary, so you can name a key and get its count back.

The good part is that looking up a key that is not there gives you 0 rather than a KeyError. A plain dictionary would stop dead at that point.

Read it as "not seen yet means zero times" and the behaviour is the obvious one.

from collections import Countercounts = Counter(["red", "blue", "red"])print(counts["red"])print(counts["green"])

Result

2
0

04 / 07

It counts strings too

Lists are not the only thing you can hand to Counter. Anything you can loop over will do.

Give it a string and it counts one character at a time. Working out which letters a piece of text leans on becomes a one-liner.

from collections import Counterprint(Counter("banana"))

Result

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

05 / 07

most_common, in order of frequency

Call most_common(n) and you get the top n, most frequent first.

What comes back is a list of (name, count) tuples. The tuples you met in Chapter 2 turn up here.

Wanting to know what came top is a genuinely common need. Think of this as the tool built for it.

from collections import Counterwords = ["red", "blue", "red", "yellow", "red", "blue"]counts = Counter(words)print(counts.most_common(2))

Result

[('red', 3), ('blue', 2)]

06 / 07

Loop over all of them in order

Call most_common() without a number and you get the lot, most frequent first.

What comes back is a list of tuples, so a for can take each one apart into two names. At this point a program that totals things up and prints them gets very short indeed.

from collections import Countercounts = Counter(["red", "blue", "red", "yellow", "red", "blue"])for word, count in counts.most_common():    print(f"{word}: {count}")

Result

red: 3
blue: 2
yellow: 1

07 / 07

If you are counting, reach for Counter

To sum up, here is everything Counter takes off your hands.

  • making an empty dictionary
  • checking whether the key is there yet
  • deciding between putting a 1 in and adding 1

All three were exactly the same every single time. When you find yourself writing the same thing repeatedly, the tool usually already exists. The only difference is whether you know about it.

Next comes something a little broader than counting: a dictionary that quietly supplies a starting value for a key that is not there yet.