Learn JavaScript

Lesson 5 of 8 ¡ First Programs: The Console, let and const, Types, typeof

Module 1 ¡ First Programs: The Console, let and const, Types, typeof

Reading Input: The Starter Every Problem Uses, Line by Line

FreeReading

In this lesson

  • Use the track's fixed starter to read numbers and words, and push every answer to out.
  • Say what each line of the starter does, and switch to the lines variant for input that holds spaces.
  • Explain why the answers are printed with one console.log at the end, using a measured time.

Zara opens her first judged problem: read some numbers, print their sum. She knows how to add. What stops her is the first line: how does a program get the numbers at all? In this track, every problem answers that with the same six lines at the top and one at the bottom, called the starter. She pastes it, writes four lines in the middle, and her program is done. This lesson takes the starter apart, so it is never a mystery again.

The starter, whole

Here it is. Every judged JavaScript problem in this track opens with exactly these lines, and you write your code where the comment says.

const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];

// your code: read with next() and nextInt(), push every line of output to out
const a = nextInt();
const b = nextInt();
out.push(a + b);

console.log(out.join("\n"));
12

That output is for the input 5 7. On the Playground, the input goes in the stdin box under the editor, and the judge feeds each hidden test the same way. The program's three lines in the middle are the whole solution to "add two numbers".

The starter's path: standard input, one string, tokens, your code, out, standard output Where the input goes, and where the answer comes out stdin 5 7 input "5 7\n" tokens "5", "7" your code nextInt() out [12] line 1 reads all at once line 2 splits lines 3 to 5 line 6 collects the last line prints out once, to stdout: 12

The starter, line by line

const input = require("fs").readFileSync(0, "utf8");   1  all of stdin, as one string
const tokens = input.split(/\s+/).filter(Boolean);     2  the string cut into words
let at = 0;                                            3  which token comes next
const next = () => tokens[at++];                       4  hand over the next token
const nextInt = () => Number(next());                  5  the next token, as a number
const out = [];                                        6  the answer lines, collected

console.log(out.join("\n"));                           last  print them all at once
  • Lines 1 and 2 run once and read everything. Your code never waits for input.
  • Lines 3 to 5 give you next() and nextInt(), the only two calls you need to read.
  • Line 6 and the last line collect your answers and print them together.
  • You do not change these lines. Your code goes between them.

So the starter turns the input into a list of words, hands them to you one at a time, and prints what you collected. The next sections open each part.

Line 1: the whole input as one string

require("fs") loads fs, Node's built-in module for files; the name stands for file system. readFileSync reads a whole file in one go. The "Sync" means the program waits until the reading is done.

The file here is 0. Every program starts with three open streams, numbered 0, 1 and 2: standard input, standard output and standard error. Reading file 0 reads standard input, which is the Playground's stdin box or the judge's test. "utf8" says to read the bytes as text, so the result is a string and Bangla letters arrive intact.

const input = require("fs").readFileSync(0, "utf8");
console.log(input.length);
console.log(input);
11
3
10 20 30

That output is for the input 3 and 10 20 30. The string holds 11 characters: the digits, two spaces and two line breaks. Printing it shows the two lines, and the empty line at the end is the input's own final line break. So line 1 gives you everything that was typed, in one string, line breaks included.

Line 2: cutting the input into tokens

Nobody wants to pick numbers out of that string by hand. Line 2 cuts it into tokens: the pieces between spaces and line breaks.

const input = require("fs").readFileSync(0, "utf8");
console.log(input.split(/\s+/));
console.log(input.split(/\s+/).filter(Boolean));
[ '3', '10', '20', '30', '' ]
[ '3', '10', '20', '30' ]

That output is for the input 3 and 10 20 30. split cuts a string wherever its pattern matches. /\s+/ is the pattern "one or more spaces, tabs or line breaks", written as a regular expression (Module 16). The square brackets show a list of values, an array, and Node prints the strings inside it with single quotes.

The first list ends with an empty string '', from the final line break. .filter(Boolean) drops the empty pieces, which is why line 2 has it. Without it, an input with a leading space or an extra blank line would hand you an empty token. So after line 2, tokens is every word of the input, in order, as strings.

Lines 3 to 5: next() and nextInt()

at is a counter that starts at 0: the position of the next token to hand over. next and nextInt are small functions, written in the short arrow form () => .... Module 5 explains arrows; here you only call them.

  • next() gives back the token at position at, then adds 1 to at. Each call hands over the next word, as a string.
  • nextInt() calls next() and turns the word into a number with Number. Despite the name, it reads 2.5 as 2.5 too.
const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];

// your code: read with next() and nextInt(), push every line of output to out
const name = next();
const age = nextInt();
const height = nextInt();
out.push(name);
out.push(typeof age);
out.push(age + 1);
out.push(height);

console.log(out.join("\n"));
Zara
number
15
1.55

That output is for the input Zara 14 1.55. Each call takes the next token, left to right. Use next() for a word and nextInt() for a number. The difference matters: next() on 14 gives the string "14", and Common mistakes shows what + does with two strings. So you read the input one token at a time, choosing the call by what the token should be.

Line 6 and the last line: collect, then print once

out starts as an empty array. Each out.push(x) adds one answer line to its end. At the very end, out.join("\n") glues the lines together with a line break between each pair, and one console.log prints the lot.

Why not call console.log for each answer? It works, and it is slow when there are many lines. Each call is a separate write to standard output. We measured it on the Playground, signed out, on 2026-10-07: one run of each program, printing the numbers 1 to 100000.

How the program prints 100000 linesTime inside the programWhole run, as the Playground reports it
console.log(i) once per line790 ms1024 ms
out.push(i), then one console.log(out.join("\n"))65 ms153 ms

About twelve times slower inside the program, for the same output. A judge gives each test a time limit, and 800 ms of printing can spend most of it before your idea is even tested. So every answer goes into out, and the last line prints them once.

Reading until the input ends

Some problems say how many values come: "the first line holds n". Others say "words, until the input ends". For both you need to repeat a few lines, which is what a loop does. Module 4 teaches loops properly; here are the two shapes, to use as given.

When n is given, repeat n times with a for loop. i counts 0, 1, 2 and stops before n.

const n = nextInt();
for (let i = 0; i < n; i++) {
  const x = nextInt();
  // use x here
}

When the input just ends, use the fact that next() gives undefined once the tokens run out. Read one token, and keep going while it is not undefined.

let word = next();
while (word !== undefined) {
  // use word here
  word = next();
}

!== means "is not exactly", the opposite of ===. The last line inside the loop reads the next token, so each pass sees a new word. When the input is used up, word becomes undefined, and the loop stops. So "n values" is a for loop that runs n times, and "until the end" is a while loop that stops at undefined.

The lines variant

Tokens lose the spaces between words. When a problem's input is a line of text with spaces, such as a sentence, you need the line whole. Those problems replace the token split with one line that cuts the input at line breaks, so next() hands over a whole line, spaces and all. Their statement says so.

const input = require("fs").readFileSync(0, "utf8");
const lines = input.split("\n");
let at = 0;
const next = () => lines[at++];
const nextInt = () => Number(next());
const out = [];

// your code: read with next() and nextInt(), push every line of output to out
// Lines variant: next() returns the next whole line, empty lines included.
const sentence = next();
out.push(sentence);
out.push(sentence.length);

console.log(out.join("\n"));
the quick brown fox
19

That output is for the input the quick brown fox. Two lines of the starter changed. Line 2 cuts the input at line breaks into lines, and line 4's next() walks through it, one whole line per call. .length counts the line's characters, spaces included, as lesson 03 showed. So for text with spaces, read lines, not tokens.

Example 1: the sum of n numbers

Kenji's stall logs n sales. He wants the total. This is the for shape with one let that grows, like lesson 02's running total.

const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];

// your code: read with next() and nextInt(), push every line of output to out
const n = nextInt();
let total = 0;
for (let i = 0; i < n; i++) {
  total = total + nextInt();
}
out.push(total);

console.log(out.join("\n"));
460

That output is for the input 5 and 120 80 45 200 15. The loop calls nextInt() exactly n times, so it reads the five sales and nothing more. The line breaks in the input do not matter: tokens come in order, whatever line they were on.

Run in Compiler
Example 2: words until the input ends

Maria pastes a list of words with no count in front. She wants to know how many there are, and which came first and last.

const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];

// your code: read with next() and nextInt(), push every line of output to out
const first = next();
let last = first;
let count = 0;
let word = first;
while (word !== undefined) {
  count = count + 1;
  last = word;
  word = next();
}
out.push(count);
out.push(first);
out.push(last);

console.log(out.join("\n"));
4
mango
lychee

That output is for the input mango banana and guava lychee. The loop stops when next() runs out and gives undefined. Zara tries an empty input: first is undefined, the loop never runs, and the program prints 0 and two empty lines. join turns undefined into an empty string. A real problem would say what to print then.

Run in Compiler
Example 3: a line of text, echoed

Amara's program reads a title and a name on two lines, where either may hold spaces, and prints a banner. This is the lines variant.

const input = require("fs").readFileSync(0, "utf8");
const lines = input.split("\n");
let at = 0;
const next = () => lines[at++];
const nextInt = () => Number(next());
const out = [];

// your code: read with next() and nextInt(), push every line of output to out
// Lines variant: next() returns the next whole line, empty lines included.
const title = next();
const author = next();
out.push("Title: " + title);
out.push("By: " + author);
out.push("Characters in the title: " + title.length);

console.log(out.join("\n"));
Title: A Garden in Sylhet
By: Amara
Characters in the title: 18

That output is for the input A Garden in Sylhet and Amara. + between a string and another value joins them into one string; Module 2 covers that in full. With tokens, the title would have arrived as four separate words.

Run in Compiler

Where this is used

  • Every judged problem in this track. The starter is fixed on purpose, so you meet one way to read input, and every problem's solution starts after the same six lines.
  • Node scripts that read a log file. Swap the 0 for a file name, readFileSync("access.log", "utf8"), and split("\n") gives one log line per entry. Small server reports are often written exactly like this.
  • Command-line pipes. On macOS and Linux, cat access.log | node count.js feeds a file into a program's standard input. The program reads it with the same readFileSync(0, "utf8"), and never knows where the text came from.

Common mistakes

1. next() where a number was meant.

const a = next();
const b = next();
out.push(a + b);

No message. For the input 10 20 it prints 1020, and the judge answers Wrong Answer. next() gives strings, and + joins two strings end to end. Use nextInt() for every number. You will reach for next() because the input looks like numbers.

2. next without its brackets.

const word = next;
out.push(word);

No message. The program prints () => tokens[at++], the function's own text. Without (), you get the function, not its result. Write next(). You will drop the brackets because elsewhere a name alone means its value.

3. One read too many.

for (let i = 0; i <= n; i++) {
  total = total + nextInt();
}

No message. With <=, the loop runs n + 1 times. The last nextInt() finds no token, gets Number(undefined), which is NaN, and the total prints as NaN. Write i < n. You will write <= because "n times" sounds as if it ends at n, and Bob learns this in every track.

4. An import line above the starter.

import os from "os";
const input = require("fs").readFileSync(0, "utf8");

On the Playground: Runtime error, with ReferenceError: require is not defined in ES module scope, you can use import instead. Node 22 sees import and runs the whole file as an ES module, where require does not exist. The starter uses require, so leave import out of judged programs. Module 11 explains the two module systems. You will add the line because modern tutorials start with import.

Brain teaser

Zara always runs the empty input first. She leaves the stdin box empty and runs this.

const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];

// your code: read with next() and nextInt(), push every line of output to out
out.push(next());
out.push(nextInt());

console.log(out.join("\n"));

What are the two lines it prints? And which value from lesson 03 is the second one?

How many tokens does an empty input have? What does tokens[0] give when the list is empty?

Exercise 1Medium

Alice has n test marks. Print their sum on the first line and their average on the second, with exactly two digits after the point. x.toFixed(2) gives the number x as a string with two decimals; Module 2 covers it.

Input. n, then n whole numbers.

Output. Two lines: the sum, then the average with two decimals.

Sample. Input 3 and 72 65 80 gives 217 and 72.33.

const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];

// your code: read with next() and nextInt(), push every line of output to out
// Read n, add up n marks with the for shape, then push the sum
// and (sum / n).toFixed(2).

console.log(out.join("\n"));

Graded as average-of-n, which the module test mounts too. The hidden tests include n = 1 and negative marks.

Run in Compiler
Exercise 2Medium

Kenji reads words until the input ends and wants the longest one. If two words share the greatest length, print the one that came first.

Input. Words separated by spaces and line breaks.

Output. The longest word.

Sample. Input tea biscuit cake gives biscuit.

const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];

// your code: read with next() and nextInt(), push every line of output to out
// Keep the best word so far in a let. Use the while shape.
// word.length gives a word's length.

console.log(out.join("\n"));

Graded as longest-word, whose statement also says what to print when the input holds no words at all.

Run in Compiler

Common doubts

  • Tutorials read input with readline or process.stdin.on. Why not here?

    Those wait for input to arrive in pieces and run your code when each piece comes, which needs ideas from Module 12. The starter reads everything first, in one line, and then your code runs top to bottom like every program so far.

  • Why require and not import?

    require belongs to CommonJS, Node's original module system, and a judged program here is one plain file. import belongs to ES modules, the newer system. Module 11 teaches both and why the judge keeps to CommonJS; Common mistakes shows what mixing them does.

  • How do I give the input when I run the file on my own computer?

    Save the input in a file and send it in: node main.js < input.txt works in a macOS or Linux terminal and in Windows Command Prompt. PowerShell has no < for this, so there write Get-Content input.txt | node main.js.

  • Does nextInt() refuse decimals?

    No. It is Number(next()), so "2.5" becomes 2.5 and "abc" becomes NaN. The name comes from contest templates in other languages, where reading a whole number is the common case.

Key takeaways

  • Line 1 reads all of standard input, file 0, as one string; line 2 cuts it into tokens.
  • next() hands over the next token as a string; nextInt() as a number.
  • Every answer goes into out with push, and the last line prints them once.
  • One console.log per line was about twelve times slower for 100000 lines in one Playground run.
  • Use a for loop when n is given, and a while loop that stops at undefined when it is not.
  • For text with spaces, the lines variant cuts the input at line breaks, so next() hands over one whole line.

Next, lesson 06 is about the reader who matters most after the judge: the human who reads your code next.

End of lesson 5

Mark it done, and your progress moves with you.

Next: Comments, Names and Code a Human Can Read