JavaRush /Courses /Go SELF /Template: read → parse → compute → print

Template: read → parse → compute → print

Go SELF
Level 2, Lesson 5
Available

1. Introduction

When you are just starting to solve problems, it is very easy to turn main() into a mess: half the lines read input, a quarter calculates something, a bit more prints, and in the middle you suddenly have string concatenation and an attempt to multiply text by a number (spoiler: Go will not appreciate it). The read → parse → compute → print template exists to make your code predictable: you always know what “stage” you are at and where to look for a bug if the result is not what you expected.

The nicest thing about this template is that it fits almost any problem with standard input/output. Even if the problem is simple, the habit of “splitting into stages” saves your nerves. And nerves, as you know, are a consumable in programming—but it is better if you spend them moderately.

General scheme: what each step means

If you describe the template in plain human language, it is literally “read → understand → calculate → say the result.” It sounds like a normal conversation, and that is good: programming for a beginner should be as “conversational” as possible, without the feeling that you are summoning ancient spirits.

Below is a diagram that is useful to keep in mind (and sometimes even write as comments in code):

flowchart LR
    A[read: read the input] --> B[parse: convert types if needed]
    B --> C[compute: calculate the result]
    C --> D[print: print exactly as required]

And a small table of “what usually lives at each stage”:

Stage What we do Typical stage result
read
read data into variables a, b, s, n got values
parse
convert a string to a number (or the other way around) n := atoi(s) or text := itoa(n)
compute
perform calculations sum, area, change, result
print
print in the required format one line/one number/several values

Important: the parse step is not always needed. If the input is already a number and we read it into an int, then there is nothing to parse. But if a number comes in “as text,” then you cannot do without Atoi.

2. Step read: read input so the next steps are convenient

At the read stage, we do the most typical work: declare variables and read values into them. Here there is often a temptation to “compute something right inside Scan,” but it is better not to rush: first extract the data, then think.

The simplest option is to read numbers straight into int:

package main

import "fmt"

func main() {
	var a, b int
	fmt.Scan(&a, &b)     // read
	fmt.Println(a + b)   // compute+print (still in one line for now)
}

This example works, but the stages are glued together. For practicing the template, it is better to separate them, even if it feels like “come on, it is just 2 lines.”

Here is the same idea, but cleaner:

package main

import "fmt"

func main() {
	// read
	var a, b int
	fmt.Scan(&a, &b)

	// compute
	sum := a + b

	// print
	fmt.Println(sum)
}

Blank lines and comments here are not decoration. They are visual boundaries: you will thank yourself later when you start making mistakes in longer problems (that is, roughly tomorrow... oh, I mean “at some point”).

3. Step parse: when input is text but you need numbers to compute

At the parse stage, we convert one data type into another. And here it is important to accept the Go philosophy: “it does not convert by itself.” At first it is annoying, but later it suddenly becomes clear why it is safer: you cannot accidentally add “12” and 3 and get “123” or 15—you must choose explicitly.

Suppose, by the problem statement, you are given a number as a string (this happens more often than it seems: codes, IDs, sometimes “0012”, etc.). Then read will read a string, and parse will turn it into an int:

package main

import (
	"fmt"
	"strconv"
)

func main() {
	// read
	var s string
	fmt.Scan(&s)

	// parse
	n, _ := strconv.Atoi(s)

	// compute
	double := n * 2

	// print
	fmt.Println(double)
}

Here we used _ to ignore the error. In training problems, this is sometimes acceptable because the input format is guaranteed: if it says “an integer is given as input,” then it is. But it is important to understand: Atoi returns (int, error), and error is a regular value that you can check and handle. In Go, it is common to work with errors explicitly as values.

If you want to at least see whether there was an error (without branching, which we are not using yet), you can simply print err:

package main

import (
	"fmt"
	"strconv"
)

func main() {
	var s string
	fmt.Scan(&s)

	n, err := strconv.Atoi(s)
	fmt.Println(n)    // if there is an error, n will be 0
	fmt.Println(err)  // <nil> if everything is OK
}

Yes, this is not “nice handling,” but for understanding the mechanics it is perfect.

4. Step compute: compute the result and keep responsibilities separate

The compute stage is where you solve the problem. It is very helpful to follow the rule: “one variable—one idea.” Beginners often put a huge formula right inside Println, and then get lost about where the error is: in arithmetic, in operator precedence, or in the fact that the input was not what they thought.

Instead, do this: put intermediate values into variables with reasonable names.

For example, suppose the task is: given the width and height of a rectangle, output the area and perimeter.

package main

import "fmt"

func main() {
	// read
	var width, height int
	fmt.Scan(&width, &height)

	// compute
	area := width * height
	perimeter := 2*width + 2*height

	// print
	fmt.Println(area, perimeter)
}

Notice: perimeter := 2*width + 2*height is easy to read because we are not trying to do “calculus under time pressure.” If you want it even clearer, you can add parentheses even if they are not needed (sometimes this is a reasonable price for readability).

5. Step print: output is part of the solution, not “we will deal with it later”

Output in training problems is tricky. You can compute the answer perfectly, but print “Answer: 42” instead of “42” and get a wrong solution. The program does not have to be polite. It has to be precise.

At the print stage, it is useful to remember a few things.

fmt.Println prints arguments separated by spaces and adds a newline. fmt.Print prints without a newline. If you output several numbers, Println is the simplest path.

package main

import "fmt"

func main() {
	x := 5
	y := 7
	fmt.Println(x, y) // 5 7
}

If you need to build a string manually (for example, you need “x=5”), then either print as arguments or use strconv.Itoa. Concatenating strings with numbers directly is forbidden.

package main

import (
	"fmt"
	"strconv"
)

func main() {
	x := 5
	line := "x=" + strconv.Itoa(x)
	fmt.Println(line) // x=5
}

6. Mini example: “Cash register”

Now we will assemble a small single application that fits the template perfectly: a mini “cash register.” The idea is simple: the input gives the price and the payment amount (in cents), the output is the change, also in cents, and then split into dollars and cents. We are not using conditions yet, so we assume the payment is always at least the price.

Let us start with a version where the input is already numbers (int). It is straightforward and pleasant.

package main

import "fmt"

func main() {
	// read
	var priceCents, paidCents int
	fmt.Scan(&priceCents, &paidCents)

	// compute
	changeCents := paidCents - priceCents
	changeDollars := changeCents / 100
	changeRestCents := changeCents % 100

	// print
	fmt.Println(changeDollars, changeRestCents)
}

Now let us make life (slightly) harder: let the price and payment come as strings. This is a common situation when the data “looks like a number” but is stored as text.

package main

import (
	"fmt"
	"strconv"
)

func main() {
	// read
	var priceStr, paidStr string
	fmt.Scan(&priceStr, &paidStr)

	// parse
	priceCents, _ := strconv.Atoi(priceStr)
	paidCents, _ := strconv.Atoi(paidStr)

	// compute
	changeCents := paidCents - priceCents
	dollars := changeCents / 100
	cents := changeCents % 100

	// print
	fmt.Println(dollars, cents)
}

Notice how predictably this reads: you literally see with your eyes where input is, where parsing is, where math is, and where output is. That is the main value of the template.

7. How to name variables so you do not get confused

Good variable names are when you can read code like a story. Bad ones are when code turns into “x1, x2, tmp, res2,” and you start guessing: is tmp temporary or permanent? and why res2, where is res1? and is x width or the cat’s age?

A convention that works well in input/output problems: name input variables by meaning (what it is), and output variables by role (what result it is).

For example, compare two variants. Formally, both work, but your brain processes them differently.

package main

import "fmt"

func main() {
	var a, b int
	fmt.Scan(&a, &b)
	c := a*b + a + b
	fmt.Println(c)
}

And now like this:

package main

import "fmt"

func main() {
	var width, height int
	fmt.Scan(&width, &height)

	area := width * height
	perimeter := 2*width + 2*height

	fmt.Println(area, perimeter)
}

In the second case, even a person who did not write this program understands what is going on. And that matters more than it seems: you yourself, in a couple of hours, are already “not the person who wrote the code” (memory likes vacations).

Below is a small hint-table of common variable naming in training problems:

Meaning Example names
dimensions
width, height, length
count
n, count, total
sum
sum, totalSum
answer
result, answer
input string
s, text, priceStr
number after parsing
n, value, priceCents

Notice: sometimes n is a perfectly fine name. But only when it really means “count” or “size,” not “I am tired of inventing names.”

8. Micro-diagnostics: printing intermediate values

When you solve a problem and get “the wrong answer,” it is tempting to immediately fall into mysticism: “the computer is broken,” “there is a bug in Go,” “the universe is against me.” In practice, most often the problem is in one of the stages: you read incorrectly, parsed incorrectly, computed incorrectly, or printed incorrectly.

While we are not using conditions, the best debugging method is to temporarily print intermediate values. And print them in a way that is easy to remove later.

For example, in the “cash register”:

package main

import "fmt"

func main() {
	var priceCents, paidCents int
	fmt.Scan(&priceCents, &paidCents)

	changeCents := paidCents - priceCents

	fmt.Println(priceCents, paidCents, changeCents) // temporary debugging

	dollars := changeCents / 100
	cents := changeCents % 100
	fmt.Println(dollars, cents)
}

Yes, this breaks the platform’s required output format. But debugging and the “final version” are different code states. The important thing is simply not to forget to remove debug lines before submission (a timeless classic).

9. Common mistakes

Mistake #1: mixing stages until it becomes “unclear what is where.”
Often a beginner writes: fmt.Scan(&a); fmt.Println("ans", a+something)—and so on throughout the program. It kind of works while the task is small. But as soon as you add string parsing, multiple inputs, or a couple of intermediate computations, the code turns into a tangle. The cure is discipline: first read, then (if needed) parse, then compute, then print, and between them—blank lines.

Mistake #2: trying to “glue a string and a number” with the + operator.
In Go, the + operator either adds numbers or concatenates strings. It does not do “both depending on mood.” Therefore "age=" + age will not compile. If you need to output them together, print as arguments (fmt.Println("age=", age)) or convert the number to a string via strconv.Itoa.

Mistake #3: parsing “just in case,” even when it is not needed.
Sometimes a student has learned Atoi and starts using it everywhere: reads an int via Scan, and then thinks “should I parse it again?” This is unnecessary and confusing. If the input is a number, read into an int and compute right away. parse is only needed when the input type does not match the type you want to work with.

Mistake #4: variable names like x, x1, x2, tmp, when meaning matters.
Short names are allowed, but they should not turn the task into a cipher. If the value is a width, let it be width. If it is a price in cents, let it be priceCents. Such names reduce the number of logical mistakes: you are less likely to swap values because they look different.

Mistake #5: incorrect output due to “friendly words.”
It is very tempting to write fmt.Println("Answer:", result)—the program looks smarter. But the judging system usually expects strictly result, without prefixes. So at the print stage, keep this rule in mind: output only what the statement asks for, and exactly in the format it asks for.

1
Task
Go SELF, level 2, lesson 5
Locked
Pages of books
Pages of books
1
Task
Go SELF, level 2, lesson 5
Locked
Code Tripler
Code Tripler
1
Task
Go SELF, level 2, lesson 5
Locked
Cash change
Cash change
1
Task
Go SELF, level 2, lesson 5
Locked
Warehouse Packing
Warehouse Packing
1
Survey/quiz
Working with integers, 2 level, 5 lesson
Unavailable
Working with integers
Working with integers
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION