Lesson 3.3
The counting pattern
Part 3: RepetitionReading, about 4 min2 exercises in this lesson
Java answers can't run on Spine yet. You can still read Java, trace it, and put an answer's lines in order.
The counting pattern
By the end of this you will be able to use a counter to answer "how many times?", and choose whether it counts every turn of a loop or only some of them.
Many questions about a loop start with "how many": how many turns did it take, how many words were typed, how many of them were yes. The answer comes from a counter, a variable that starts at 0 and goes up by 1 each time the thing you are counting happens.
Counting turns
Mia wants to buy a game. She saves 20 every day, starting from nothing. This program reads the price and counts how many days she must save before she has enough.
price = int(input())
saved = 0
days = 0
while saved < price:
saved = saved + 20
days = days + 1
print("Days: " + str(days))import java.util.Scanner;
public static void main(String[] args) {
Scanner scanner
= new Scanner(System.in);
int price = Integer.parseInt(
scanner.nextLine());
int saved = 0;
int days = 0;
while (saved < price) {
saved = saved + 20;
days = days + 1;
}
System.out.println("Days: " + days);
}Here is a trace when the user types 70.
| Turn | saved at the start | saved at the end | days at the end |
|---|---|---|---|
| 1 | 0 | 20 | 1 |
| 2 | 20 | 40 | 2 |
| 3 | 40 | 60 | 3 |
| 4 | 60 | 80 | 4 |
After turn 4 she has 80, so saved < price is false and the loop stops. It prints Days: 4. Two variables change on every turn: saved is what the condition tests, and days is the counter. The counter goes up once per turn, so when the loop ends it holds the number of turns.
The three lines of a counter
A counter has the same shape in every program:
- Before the loop: give it a starting value, nearly always 0.
- Inside the loop: add 1 when the thing you count happens.
- After the loop: use it, for example print it.
Spotting this shape again and again is pattern recognition: once you know it, every new "how many" question starts from the same three lines.
Why 0? Before the first turn, nothing has been counted yet. And a loop can run zero times: if the game is free and the user types 0, then saved < price is false at the first check, the body never runs, and the program prints Days: 0, which is right. Start at 0 unless you can say exactly what has already been counted before the loop begins.
Counting matches
Sometimes you do not want every turn, only the turns where something is true. Then the line that adds 1 goes inside an if. This program reads votes until the word end, and counts both all the votes and the yes votes.
votes = 0
yes = 0
answer = input()
while answer != "end":
votes = votes + 1
if answer == "yes":
yes = yes + 1
answer = input()
print("Yes: " + str(yes)
+ " of " + str(votes))import java.util.Scanner;
public static void main(String[] args) {
Scanner scanner
= new Scanner(System.in);
int votes = 0;
int yes = 0;
String answer = scanner.nextLine();
while (!answer.equals("end")) {
votes = votes + 1;
if (answer.equals("yes")) {
yes = yes + 1;
}
answer = scanner.nextLine();
}
System.out.println("Yes: " + yes
+ " of " + votes);
}If the user types yes, no, yes, then end, it prints Yes: 2 of 3. The two counters differ only in where their add-1 line sits:
| Counter | Where it goes up | What it counts |
|---|---|---|
votes | In the loop body, outside the if | Every turn |
yes | Inside the if | Only turns where the answer is yes |
Look at the read at the end of the body. It is outside the if, so it runs on every turn. If it were inside the if, a no vote would never be followed by a new read, and the loop would run forever. That is the missing update from the last lesson, hiding inside an if.
Two common slips
- Starting at 1 when nothing has been counted yet. The counter is then one too many every time, even when the loop never runs.
- Adding 1 in the wrong place. Inside the
ifcounts matches, outside it counts turns. Before you write the line, say which one the question asks for.
Now try it yourself on the questions below.
Exercise 3.3.13.3.1 · Write itHalving steps
Write a program that reads a whole number and counts how many times it can be halved (using whole-number division) before it reaches 0.
- Read one number on a single line.
- Repeatedly divide the number by 2, keeping only the whole-number part, and count each division.
- Stop when the number reaches 0.
- Print
Steps:followed by the count. - If the number is already 0, the count is 0.
The number is always 0 or positive. Your program is run several times. Only what it prints is checked.
In Python, use // for whole-number division. In Java, / between two ints already drops the fraction.
Running Java here comes later. You can put this answer's lines in order instead. You can still write your Java answer (it stays while this page is open) and compare it with our worked solution. Or try this exercise in Python.
Examples
Your program is run 6 times: the 3 examples below, and 3 hidden ones that check the rules above. Only what it prints is checked.
8 halves to 4, 2, 1, 0 in four steps (rule 2)
You type
- typed: 8
It prints
Steps: 4
1 halves to 0 in one step (rule 2)
You type
- typed: 1
It prints
Steps: 1
already 0, no steps needed (rule 5)
You type
- typed: 0
It prints
Steps: 0
Exercise 3.3.23.3.2 · Write itCount the digits
Write a function that returns how many digits a whole number has, using a loop that keeps going while there are digits left to count.
nis a whole number from 0 up to 2147483647.- 0 has one digit.
- Do not turn the number into text in any way (including f-strings in Python or
"" + nin Java), and do not use logarithms. The shortcuts listed with this question are not allowed.
Only the number your function returns is checked.
def digit_count(n: int) -> int
You cannot use these in this question:
- str()
- len()
- repr()
- format()
- ascii()
- .format()
- .__str__()
- .__repr__()
- .__format__()
- import math
- import decimal
- import cmath
This question is about writing a loop that stops at the right time, so turning the number into text or using logarithms is not allowed.
Examples
Your function is tested on 9 cases: the 3 examples below, and 6 hidden ones that check the rules above.
- digit_count(472) should return 3: three digits
- digit_count(0) should return 1: zero has one digit (rule 2)
- digit_count(10) should return 2: the smallest number with two digits
public static int digitCount(int n)
Running Java here comes later. You can put this answer's lines in order instead. You can still write your Java answer (it stays while this page is open) and compare it with our worked solution. Or try this exercise in Python.Checking whether Java answers can run here.
You cannot use these in this question:
- String.valueOf()
- Integer.toString()
- Long.toString()
- String.format()
- Integer.toUnsignedString()
- Math.log10()
- Math.log()
- .length()
- .toCharArray()
- .chars()
- .codePoints()
- .split()
- .getBytes()
- .charAt()
- .toString()
- .precision()
- .indexOf()
- import java.math
This question is about writing a loop that stops at the right time, so turning the number into text or using logarithms is not allowed.
Examples
Your function is tested on 9 cases: the 3 examples below, and 6 hidden ones that check the rules above.
- digitCount(472) should return 3: three digits
- digitCount(0) should return 1: zero has one digit (rule 2)
- digitCount(10) should return 2: the smallest number with two digits