Counting & Frequency
Counting one thing is a counter. Counting everything at once — how many 1s, how many 2s, how many of each — is a different problem, and trying to solve it with counters is what makes people inventcount_1, count_2, count_3. The answer is a dictionary, and this is the program it was invented for.
1Program 1 — how many times does one value appear?
Count how many times 6 was rolled, in a tuple of dice rolls.
# how many sixes?
rolls = (3, 6, 2, 6, 4, 6, 1)
wanted = 6
count = 0
for r in rolls:
if r == wanted:
count = count + 1
print(wanted, 'appeared', count, 'times')6 appeared 3 times
count = count + 1, not count = count + r. A counter goes up by one per match; a total goes up by the item. Mixing them up here would report “6 appeared 18 times”, which is obviously wrong — and only if you look.The built-in does the same job in one call, and it is what you would write unless the question says not to:
rolls = (3, 6, 2, 6, 4, 6, 1)
print(rolls.count(6))
print(rolls.count(5))3 0
count() answers 0 rather than raising anything for a value that never appears — which is the opposite of index(), and worth remembering because the two look like a pair.
2Program 2 — counting the ones that pass a test
Count the even and the odd numbers in a tuple.
# two counters, one if…else
numbers = (12, 7, 30, 45, 8, 21, 64)
evens = 0
odds = 0
for n in numbers:
if n % 2 == 0:
evens = evens + 1
else:
odds = odds + 1
print('Even:', evens)
print('Odd: ', odds)Even: 4 Odd: 3
The check that it worked: 4 + 3 = 7, which is len(numbers). Every item landed in exactly one of the two, which is what an else guarantees and two separate ifs would not.
count() cannot do this one. It matches a value, not a rule — there is no way to ask it for “everything even”.
# the same shape, on a pass mark
marks = (56, 28, 91, 33, 12, 78, 65)
passed = 0
failed = 0
for m in marks:
if m >= 33:
passed = passed + 1
else:
failed = failed + 1
print('Passed:', passed)
print('Failed:', failed)Passed: 5 Failed: 2
3Program 3 — the frequency of every value
For a tuple of dice rolls, report how many times each face came up.
A counter holds one number. Here the answer is six numbers — one per face — and they are not known in advance: on a tuple of names or colours you would not know how many counters to make. What is needed is a box that can grow a new compartment whenever an unseen value turns up, with the value itself as the label. That is a dictionary.
# tally every value into a dictionary
rolls = (3, 6, 2, 6, 4, 6, 1, 2)
freq = {}
for r in rolls:
if r in freq:
freq[r] = freq[r] + 1
else:
freq[r] = 1
print(freq){3: 1, 6: 3, 2: 2, 4: 1, 1: 1}freq = {}An empty dictionary — the collector, made before the loop. {} is empty; () would be an empty tuple and [] an empty list.
if r in freq:Has this face been seen before? On a dictionary, `in` asks about the KEYS, so this is 'is there already a compartment labelled 3?'
freq[r] = freq[r] + 1Seen before: read the count out, add one, put it back. The same shape as count = count + 1, with the counter picked by name.
freq[r] = 1First sighting: make the compartment and put 1 in it. Not 0 — you are looking at one right now.
sorted(), which the next chapter uses.4The same thing with get()
get() asks for a key and takes a fallback for when the key is missing. That collapses the whole if…else into one line:
# the same tally, in one line inside the loop
rolls = (3, 6, 2, 6, 4, 6, 1, 2)
freq = {}
for r in rolls:
freq[r] = freq.get(r, 0) + 1
print(freq){3: 1, 6: 3, 2: 2, 4: 1, 1: 1}Read freq.get(r, 0) as “the count for r, or 0 if there is not one yet”. On a face never seen it hands back 0 and 0 + 1 makes the first entry; on a face seen before it hands back the running count. Same answer, four lines shorter, and it is the version experienced Python programmers write.
It works on anything a tuple can hold, not just numbers:
# the keys can be strings just as easily
words = ('red', 'blue', 'red', 'green', 'blue', 'red')
freq = {}
for w in words:
freq[w] = freq.get(w, 0) + 1
print(freq){'red': 3, 'blue': 2, 'green': 1}5Program 4 — which value appears most often?
The champion program again, with count() doing the measuring:
# the value that turns up most often
rolls = (3, 6, 2, 6, 4, 6, 1, 2)
best = rolls[0]
best_count = rolls.count(rolls[0])
for r in rolls:
if rolls.count(r) > best_count:
best = r
best_count = rolls.count(r)
print('Most common:', best, '-', best_count, 'times')Most common: 6 - 3 times
rolls.count(r) walks the whole tuple, and it is called once per item — so an eight-item tuple is walked eight times over. Building the freq dictionary first and finding the champion in it walks the data twice in total. On eight rolls nobody notices; the habit is worth having anyway.The statistics module has a name for this value — the mode — and computes it in one call. That is the last chapter of this course.
6Recap
count = count + 1. A total goes up by the item. They look alike and answer different questions.
rolls.count(6) is fine; 'how many even' has to be a loop with an if.
Unlike index(), which raises ValueError. The pair does not behave as a pair.
freq = {} above the loop, freq[x] = freq.get(x, 0) + 1 inside it. That one line is the whole idea.
- 1
Count how many marks in a tuple are 75 or above.
Hint · One counter, one
if. Up by 1, not by the mark. - 2
Count how many names in a tuple start with the letter
S.Hint ·
if n[0] == 'S':— orn.startswith('S'), which reads better. - 3
Tally the grades in a tuple like
('A', 'B', 'A', 'C').Hint · The
get()line, unchanged. The keys happen to be letters; nothing else is different. - 4
From the frequency dictionary, print only the values that appeared more than once.
Hint · Build
freqfirst, then walk it — which is exactly what the next chapter is about.
Why is a dictionary the right tool for counting every value at once?
What does freq.get(r, 0) hand back for a value never seen before?
rolls = (3, 6, 2, 6, 4, 6, 1, 2). Why does the tally print starting with 3?