Module 2 ¡ Types, Operators and Coercion: Why '5' + 2 Is Not 7
Problems: Types and Coercion
In this lesson
- Read each value with the right reader:
nextInt()for a number,next()for text,BigInt(next())for an exact big integer, and the lines variant for empty lines. - Print every number exactly as JavaScript prints it, and explain why
-0prints0and0.1 + 0.2prints 17 digits. - Test the edges the hidden tests try before you submit:
-0,NaN,Infinity, an empty line and the largest safe integer.
Ten problems, graded against hidden tests on Node 22, the same JavaScript the Playground runs. Eight of them you met inside the lessons of this module, and bigint-sum was in the Interview Pack. Two are new, messy-measurements and truthy-or-falsy, and both are medium.
Problems 1, 2 and 4 (sum-and-join, clean-numbers and largest-of-three) are free for everyone. The other seven are Pro problems: locks per problem arrive in a later release, and until then all ten are open. The module test has two problems, calculator and clean-numbers, so both are worth solving here first.
Bob reads the sample, writes the first program that prints it, and submits. Zara feeds her program -0, NaN and an empty line before she even looks at the sample. In this set, every hidden test is a value that coercion treats in its own way, so Zara's habit earns the marks.
nextInt() for a number, next() for text
The starter splits the whole input into tokens. A token is a piece of text between spaces or line breaks, and every token is a string. next() hands you the next token as it is, a string. nextInt() is Number(next()): the same token, converted to a number.
So the reader you call decides the type, before any operator runs. Read a value you will add or compare as a number with nextInt(). Read a word, an operator or a typed token like num:5 with next(). When you need both the text and the number, as sum-and-join does, read once with next() and convert with Number().
Two problems need a different reader. bigint-sum adds integers up to 1018, past the largest safe integer, so it reads each one with BigInt(next()). given-or-default and missing-empty-zero use the lines variant of the starter. There const lines = input.split("\n"); replaces the token split, so next() returns a whole line, and an empty line arrives as "".
The diagram follows one input through a whole program. The top row is the right path for 5 2; the dashed row is Bob's.
Both rows read the same two tokens and end in a text the judge reads. Only the convert box differs, so the type of a value is settled the moment you read it.
The judge compares text, so print what JavaScript prints
The judge runs your whole program on a hidden input and compares what it prints, line by line. Spaces at the end of a line are ignored. It never sees your numbers, only the text they became. Every number you push into out becomes text when out.join("\n") runs, and that text is exactly what String() gives.
"As JavaScript prints it", in every statement here, means that text. Most numbers print the way you expect. A few print in a way you must know before the judge shows you:
console.log(String(-0));
console.log(String(0.1 + 0.2));
console.log(String(7 / 2));
console.log(String(1 / 0), String(-1 / 0), String(0 / 0));
console.log(String(1e20), String(1e21));
console.log(String(0.000001), String(0.0000001));
console.log(String(9007199254740993));
0
0.30000000000000004
3.5
Infinity -Infinity NaN
100000000000000000000 1e+21
0.000001 1e-7
9007199254740992
Line 1: -0 is a real number, but String() prints it as 0. Line 2 is the double rounding Module 1 showed, printed in full. Line 4: a division by zero is not an error in JavaScript, and its results print as words.
Line 5: from 1021 upward a number prints in exponent form, and line 6 does the same below 10-6. Line 7: 9007199254740993 is past 253, so the number already holds 9007199254740992 before it prints. So never format a number by hand for these statements: push it, and the starter's out.join prints it the way the judge expects.
The edges the hidden tests try
Every problem has 11 to 16 hidden tests. They run from the smallest input to the largest the constraints allow, and each test file stays under 1 MiB. Between those two sits every value this module taught you to fear. The table names them, so you can try them first.
| Problem | Access | Tests | What the hidden tests try |
|---|---|---|---|
sum-and-join | Free | 16 | -0 -0, leading zeros, 0.1 0.2, 253 - 1 plus 1, tokens of 21 and 25 digits |
clean-numbers | Free | 12 | 0x1f and -0x1f, the 0b and 0o forms, Infinity spelled four ways, 1e400, 1_000, Bangla digits, 30000 tokens |
calculator | Pro | 11 | 1 / 0, 1 / -0, 0 / 0, results of -0, sums past 253, results printed with e+21 and e-7, 10000 lines |
largest-of-three | Free | 12 | three equal numbers, all negative, -0 beside 0, 2.50, leading zeros, numbers whose text order and number order disagree, 10000 lines |
given-or-default | Pro | 11 | empty lines in a row, NULL, null with a space after it, fields of spaces, 0 and false, Bangla text, 10000 fields |
messy-measurements | Pro | 12 | 1e3m, 0x1f, -0kg, 1.2.3, a lone . or -, Infinityx, 40000 tokens |
truthy-or-falsy | Pro | 11 | all sixteen names in both orders, minus-zero and zero-bigint, repeats, 40000 names |
three-equalities | Pro | 11 | the twelve pairs both ways round, every pair of twenty values (400 lines), str:0x10 and str:1e3, 20000 lines |
missing-empty-zero | Pro | 11 | empty lines, 0.0, 0x0 and -0, NaN and Null as text, 007, 1e21, 20000 lines |
bigint-sum | Pro | 12 | n = 1, 9007199254740993 alone, +5 and -007, 40000 values of 1018, a total of 0 |
Try the small edges on the Playground. Its stdin box takes at most 10000 characters, so it cannot hold the largest tests. That limit belongs to the box, not to the judge. A test you write yourself with one edge in it says more than a big one anyway.
The forms these ten problems need
const a = nextInt(); a number: Number(next())
const word = next(); a token, kept as text
const line = next(); lines variant: one whole line, "" when empty
String(x) x as JavaScript prints it; out.join does the same
Number.isNaN(x) true for NaN and for nothing else
parseFloat(t) the number at the start of t, or NaN
x ?? "default" the right side only when x is null or undefined
x == null true for null and undefined, nothing else
a > b ? a : b the larger of a and b
Object.is(x, y) like ===, but NaN is NaN and 0 is not -0
let sum = 0n; sum += BigInt(t); an exact sum of integers
if (value) { ... } runs when value is truthy
- Every starter below is the fixed starter of the track. Keep its lines, and write your code where the comment says.
- A plain
forloop andifare enough for every problem. You met them in Module 1, lesson 05, and Module 4 teaches them. - Push one line of output per answer. Words are printed exactly as the statement writes them, in lower case.
Kenji's scoreboard reads two scores and says whether the first is smaller. He reads them with next() and compares. Here is what he gets, beside the comparison of the numbers.
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 = [];
const a = next();
const b = next();
out.push(typeof a + " " + typeof b);
out.push(String(a < b));
out.push(String(Number(a) < Number(b)));
console.log(out.join("\n"));
string string
true
false
That output is for the input 10 9. Both tokens are strings, as line 1 shows. Two strings compare character by character, and "1" comes before "9", so "10" < "9" is true. As numbers, 10 is not smaller than 9.
No error appears, and the program runs. This is why largest-of-three asks you to read with nextInt(): a program that compares tokens passes many tests and fails the ones where the lengths differ.
Zara converts distances from metres to kilometres. The input is n, then n distances. Each line of output is a distance divided by 1000, as JavaScript prints it.
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 = [];
const n = nextInt();
for (let i = 0; i < n; i++) {
const metres = nextInt();
out.push(String(metres / 1000));
}
console.log(out.join("\n"));
1.5
0
0.3
0.0001
5e-7
1e+21
That output is for the input 6 and 1500 -0 300 0.1 0.0005 1e24. -0 divided by 1000 is still -0, and it prints as 0. 0.0005 / 1000 is below 10-6, so it prints as 5e-7, and 1021 prints as 1e+21.
Nothing here is wrong. A judge that expects String()'s text gets exactly these lines, and so does calculator. A program that formats numbers itself, with toFixed for example, prints 0.00 for the fifth line and fails.
Bob prints a receipt. The input is n, then n lines, each an item name and a price. He prints each item, then the total twice: as JavaScript prints it, and with two decimals for the customer.
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 = [];
const n = nextInt();
let total = 0;
for (let i = 0; i < n; i++) {
const item = next();
const price = nextInt();
total = total + price;
out.push(item + " " + String(price));
}
out.push("total " + String(total));
out.push("shown " + total.toFixed(2));
console.log(out.join("\n"));
pen 0.1
eraser 0.2
ruler 0.3
total 0.6000000000000001
shown 0.60
That output is for the input 3, then pen 0.1, eraser 0.2 and ruler 0.3. Each line reads a word with next() and a price with nextInt(), the two readers side by side. The total is the double rounding again, and toFixed(2) hides it in a string with two decimals.
Which line is right depends on the statement, never on taste. Every statement in this set says "as JavaScript prints it", so the total line is the one to print. A statement that wanted two decimals would say so, and then toFixed(2) would be right.
Where this is used
- The browser's
URLSearchParams. Itsget("q")returnsnullwhen the address has noq, and""for?q=. Telling those two apart is the job ofmissing-empty-zero. - HTML number inputs. An
<input type="number">hands itsvalueto JavaScript as a string, even when it shows digits. ItsvalueAsNumberproperty gives the number, andNaNfor an empty box. - Twitter's API, version 1.1. Tweet ids are 64-bit integers, past 253, so its JSON sent each one twice: as
id, a number, and asid_str, a string. JavaScript code readid_str, because the number had already rounded. Version 2 of the X API sends ids only as strings. - Stripe's payment API. Every amount is an integer in the smallest unit of the currency, such as cents. A charge of 10.50 dollars is sent as
1050, so the 0.1 + 0.2 of Example 3 never touches money.
Common mistakes
1. Reading a number with next().
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 = [];
const a = next();
const b = next();
out.push(String(a + b));
console.log(out.join("\n"));
52
That is the output for the input 5 2. No error appears, and the Playground's verdict is Success, so only the judge's Wrong Answer tells you. Both tokens are strings, and + joins strings. You will make this mistake because -, * and / convert by themselves and hide it. Read with nextInt().
2. Starting a BigInt sum at 0.
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 = [];
const n = nextInt();
let sum = 0;
for (let i = 0; i < n; i++) {
sum += BigInt(next());
}
out.push(String(sum));
console.log(out.join("\n"));
TypeError: Cannot mix BigInt and other types, use explicit conversions
That is the input 2 and 1 2. The Playground's verdict is Runtime error, and nothing reaches stdout, because the throw comes before the last line. 0 is a number and BigInt(next()) is a bigint, and + refuses to mix the two. Start the sum at 0n.
3. BigInt(nextInt()).
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 = [];
const n = nextInt();
let sum = 0n;
for (let i = 0; i < n; i++) {
sum += BigInt(nextInt());
}
out.push(String(sum));
console.log(out.join("\n"));
9007199254740992
That is the input 1 and 9007199254740993, and the answer is one short. nextInt() made a number first, and the number had already rounded to 9007199254740992. BigInt() then copied the rounded value exactly. Give BigInt the text: BigInt(next()).
4. || where ?? was meant.
const answer = "";
const count = 0;
console.log("[" + (answer || "default") + "]");
console.log("[" + (answer ?? "default") + "]");
console.log(count || 10, count ?? 10);
[default]
[]
10 0
No error, just the wrong value. || replaces every falsy value, so an empty answer and a count of 0 vanish. ?? replaces only null and undefined. You will reach for || because older code uses it everywhere, from before ?? joined the language in ES2020.
Bob read two numbers with next(), added them, and got 52 for 5 and 2. Now he wants both answers side by side, the sum and the join, so he never mixes them up again. Read the two tokens with the starter's next() and nextInt().
Input. One line with two tokens a and b, separated by a space. Each token is a decimal number: an optional minus sign, one or more digits, and optionally a decimal point followed by one or more digits. Leading zeros may appear.
Output. Two lines. Line 1 holds the sum of a and b as numbers, printed the way JavaScript prints a number: what String() gives for it. Line 2 holds the two tokens joined as text, a first, exactly as they were typed.
Constraints. Each token has 1 to 25 characters.
Sample. Input 5 2 gives 7 and 52 on two lines.
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
// Line 1: a and b added as numbers. Line 2: a and b joined as text.
console.log(out.join("\n"));
Run in Compiler
Hint 1
Every token arrives as a string. Which output line needs the strings as they are, and which needs numbers?
Hint 2
Read each token once with next() and keep it in a const. Line 2 is a + b on the two strings. Line 1 converts both with Number() before it adds.
Solution
const a = next() and const b = next() keep the two strings. Number(a) + Number(b) adds, and a + b joins, because + joins as soon as one side is a string. Push the sum through String(), or push the number and let out.join turn it into text: both give the same characters.
Reading with nextInt() twice loses the typed text, so line 2 prints 73 for 007 3 instead of 0073. parseInt drops the fraction and prints -2 for -3.5 1.25, where -2.25 is right. The hidden tests also try -0 -0, whose sum prints 0 while the join prints -0-0, and 25-digit tokens whose sum prints as 2e+25.
Zara gets a list of tokens from a sensor log, and some of them are junk. She wants to know which ones are clean numbers. A token is clean when Number(token) is not NaN. Read the input with the starter's nextInt() and next().
Input. The first line holds n. The second line holds n tokens, separated by spaces. No token contains a space.
Output. n lines, one per token, in the input order. For a clean token, print yes, a space, and the number as JavaScript prints it: String(Number(token)). Otherwise print no.
Constraints. 1 <= n <= 30000. Each token has 1 to 20 characters.
Sample. Input 5 and 12 3.50 abc 007 12px gives yes 12, yes 3.5, no, yes 7 and no on five lines.
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, then n tokens. Per token: "yes " and the number, or "no".
console.log(out.join("\n"));
Run in Compiler
Hint 1
Number() reads the whole token or gives NaN. What does it give for 0x1f, Infinity and 1e3? Run them before you guess.
Hint 2
For each token, compute Number(token) once and keep it. Test it with Number.isNaN, then push "yes " + String(value) or "no".
Solution
The test is Number.isNaN(value), which is true for NaN and nothing else. Every other value counts as clean, Infinity included, because the statement asks only about NaN. String(value) then prints 7 for 007, 31 for 0x1f and 1000 for 1e3.
parseFloat is the wrong reader here: it says 12 for 12px. Echoing the token prints 007 and 3.50 as typed, and the sample catches it. Number.isFinite says no to Infinity, which is clean. The hidden tests add -0x1f (no sign is allowed before 0x), 1_000 and the Bangla digits ⧧⧍, all three no.
Alice is building a pocket calculator for her shop. Each line she types is a number, an operator and another number, and the calculator prints the result. Bob's first version printed 52 for 5 + 2, so Alice wants it done right. Read the input with the starter's nextInt() and next().
Input. The first line holds n, and n lines follow, each a op b: a number, a space, an operator, a space and a number. The operator is one of +, -, * and /. Each number is written in decimal: an optional minus sign, one or more digits, and optionally a decimal point followed by one or more digits. Leading zeros may appear.
Output. n lines. Line i holds the result of a op b for line i, computed on numbers and printed the way JavaScript prints a number. A division by zero prints what JavaScript gives: Infinity, -Infinity or NaN.
Constraints. 1 <= n <= 10000. Each of a and b has 1 to 20 characters.
Sample. Input 5, then 5 + 2, 7 - 10, 6 * 7, 7 / 2 and 1 / 0 on five lines, gives 7, -3, 42, 3.5 and Infinity on five lines.
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, then n lines of a, op and b. Per line: the result as JavaScript prints it.
console.log(out.join("\n"));
Run in Compiler
Hint 1
If a and b stayed strings, which of the four operators would still give the right answer, and which one would not?
Hint 2
Read a with nextInt(), the operator with next() and b with nextInt(). Pick the operation with if and else if on the operator, then push String(result).
Maria logs three temperature readings a day and wants the largest of each day. Kenji says to call Math.max and be done. This problem trains the ternary operator instead, so the rule is ? : only. Read the input with the starter's nextInt(). Find each largest with ? :, with no Math.max and no if; the judge checks only your output, so that rule is yours to keep.
Input. The first line holds t. Then t lines follow, each with three numbers separated by spaces. Each number is written in decimal: an optional minus sign, one or more digits, and optionally a decimal point followed by one or more digits. Leading zeros may appear.
Output. t lines. Line i holds the largest of the three numbers on input line i, printed the way JavaScript prints a number.
Constraints. 1 <= t <= 10000. Each number has 1 to 20 characters.
Sample. Input 3, then 3 9 4, -5 -2 -9 and 10 9 100, gives 9, -2 and 100 on three lines.
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 t, then t lines of three numbers. Per line: the largest, found with ? : only.
console.log(out.join("\n"));
Run in Compiler
Hint 1
Which is larger, "9" or "100", as strings? And as numbers? Example 1 above has the answer.
Hint 2
Read all three with nextInt(). First keep the larger of a and b with a > b ? a : b. Then compare that one with c the same way.
Solution
Two ternaries, each answering one question: const largerOfAB = a > b ? a : b;, then largerOfAB > c ? largerOfAB : c. No nesting is needed, and each line reads like a sentence. With numbers, the comparison is numeric, and String() prints 007 as 7 and 2.50 as 2.5.
Reading with next() compares text and prints 9 for the sample's third line. Printing the winning token as typed prints 007 where 7 is wanted. A nested ternary written in a hurry, such as a > b ? (a > c ? a : c) : (b > a ? b : c), prints 4 for 5 5 4, because equal a and b fall through to c.
David's sign-up form sends every field as one line of text. A field nobody filled in arrives as null or undefined, and David shows the word default for it. An empty answer is still an answer, and so is 0. This problem uses the lines variant of the starter: const lines = input.split("\n"); replaces the token split, so next() returns the next whole line, empty lines included. Read n with nextInt().
Input. The first line holds n, and n lines follow, one field each. A line that is exactly null stands for the value null. A line that is exactly undefined stands for undefined. Any other line, an empty line included, is the text itself.
Output. n lines, one per field: [, then value ?? "default", then ]. The brackets show every space and every empty text.
Constraints. 1 <= n <= 10000. Each field line has 0 to 60 characters, and the last one is never empty. Every line ends with a newline.
Sample. Input 5, then Alice, null, an empty line, 0 and undefined, gives [Alice], [default], [], [0] and [default] on five lines.
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.
// Read n, then n fields. Per field: "[" + (value ?? "default") + "]".
console.log(out.join("\n"));
Run in Compiler
Hint 1
Which two values does ?? replace? Is an empty line one of them? Is the text "0"?
Hint 2
For each line, start with let value = line;. Set it to null or undefined only when the line is exactly that word. Then push "[" + (value ?? "default") + "]".
Amara copies measurements out of a design file and a shop catalogue, and every one comes with its unit glued on: 12px, 3.5kg. She needs only the number at the start of each token. Read the input with the starter's nextInt() and next().
Input. The first line holds n. The second line holds n tokens, separated by spaces. No token contains a space.
Output. n lines, one per token, in the input order. Print String(parseFloat(token)), or the word invalid when parseFloat(token) is NaN.
Constraints. 1 <= n <= 40000. Each token has 1 to 20 characters.
Sample. Input 5 and 12px 3.5kg -4.5c px12 .5m gives 12, 3.5, -4.5, invalid and 0.5 on five lines.
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, then n tokens. Per token: the number at its start, or "invalid".
console.log(out.join("\n"));
Run in Compiler
Hint 1
Number("12px") is NaN. Which converter reads a number from the start of a text and ignores what follows?
Hint 2
Keep parseFloat(token) in a const. Push "invalid" when Number.isNaN says so, and String(value) otherwise.
Maria keeps asking why an empty array counts as true in an if. Zara makes a table of sixteen values with a short name for each. For every name, the program says whether if treats its value as true (truthy) or as false (falsy). Read the input with the starter's nextInt() and next().
Input. The first line holds n. Then n lines follow, each holding one name from this table. Each name stands for the JavaScript value beside it.
| Name | Value | Name | Value |
|---|---|---|---|
false | false | true | true |
zero | 0 | minus-zero | -0 |
zero-bigint | 0n | empty-string | "" |
space-string | " " | zero-string | "0" |
false-string | "false" | null | null |
undefined | undefined | nan | NaN |
empty-array | [] | empty-object | {} |
infinity | Infinity | minus-one | -1 |
Output. n lines, one per name, in the input order: the name, a space, then truthy or falsy.
Constraints. 1 <= n <= 40000. Every name is one of the sixteen in the table, and a name may repeat.
Sample. Input 5, then zero, empty-string, zero-string, empty-array and nan on five lines, gives zero falsy, empty-string falsy, zero-string truthy, empty-array truthy and nan falsy.
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, then n names. Per name: the name, a space, then truthy or falsy.
console.log(out.join("\n"));
Run in Compiler
Hint 1
Write each name's value as a JavaScript literal. How many of the sixteen are falsy? Count them before you write a line.
Hint 2
Turn the name into its value with an if and else if chain, then let if (value) decide. Do not keep your own list of falsy names.
Kenji's code review says "never use ==". Maria wants to see what == actually does, next to === and Object.is, for any two values. Zara writes each value as a typed token, so a program can build the value back from the text. Read the input with the starter's nextInt() and next(). token.slice(4) gives the part of a token after its first four characters, such as the text after num:; Module 3 teaches slice.
Input. The first line holds n. Then n lines follow, each with two tokens x and y, separated by a space. A token is one of these:
num:and a text: the numberNumber(text), such asnum:-0,num:NaNornum:Infinity;str:and a text: the string text itself, andstr:alone is the empty string"";bool:trueorbool:false: the boolean;nullorundefined: that value.
Output. n lines. Line i holds three words for the pair on input line i: x == y, x === y and Object.is(x, y), each true or false, separated by single spaces.
Constraints. 1 <= n <= 20000. Each token has at most 25 characters and no spaces. The text after num: is never empty.
Sample. The sample is the twelve pairs of lesson 04's chart. Input 12, then num:1 str:1, num:0 str:, num:0 str:0, str: str:0, null undefined, null num:0, undefined num:0, num:NaN num:NaN, num:0 num:-0, bool:true num:1, bool:true str:true and bool:false str:0 on twelve lines. It gives true false false three times, false false false, true false false, false false false twice, false false true, true true false, true false false, false false false and true false false.
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, then n lines of two typed tokens such as num:1 and str:1.
// Per line: x == y, x === y and Object.is(x, y), separated by spaces.
console.log(out.join("\n"));
Run in Compiler
Hint 1
Build the real value from each token first, and only then compare. What does num:-0 become? And str:?
Hint 2
Look at token.slice(0, 4): for num: and str:, the value comes from token.slice(4). The other four tokens are whole words. Then push String(x == y), String(x === y) and String(Object.is(x, y)), joined by spaces.
Bob's form reader writes value || "missing", and his report says missing for a quantity of 0 and for a field left empty. Amara wants three different words for three different things: nothing arrived, an empty answer arrived, and a zero arrived. This problem uses the lines variant of the starter: const lines = input.split("\n"); replaces the token split, so next() returns the next whole line, empty lines included. Read n with nextInt().
Input. The first line holds n, and n lines follow. Decode each line into a value, in this order. A line that is exactly null is null, and exactly undefined is undefined. An empty line is the empty string "". Any other line is Number(line) when that is not NaN, and otherwise the line's text.
Output. n lines, one per value. Print missing when value == null, empty when value === "", and zero when value === 0. Otherwise print value, a space and String(value).
Constraints. 1 <= n <= 20000. Each of the n lines has 0 to 20 characters, never starts or ends with a space, and the last one is never empty.
Sample. Input 7, then null, 0, an empty line, 12, abc, undefined and -0, gives missing, zero, empty, value 12, value abc, missing and zero on seven lines.
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.
// Decode each line, then print missing, empty, zero or value and the value.
console.log(out.join("\n"));
Run in Compiler
Hint 1
What is Number("")? So in which order must the decoding steps run?
Hint 2
Decode null, undefined and the empty line by exact comparison first, then try Number(line). Print with one value == null check, then === "", then === 0.
Zara's game server keeps every player's points as a whole number, up to 1018 each. The season total is the sum of them all. Added as ordinary numbers, the total loses its last digits once it passes 253, so Zara wants it exact. Read n with the starter's nextInt() and each integer with next().
Input. The first line holds n. The second line holds n integers, separated by spaces. Each integer is written in decimal, with an optional + or - sign, and leading zeros may appear.
Output. One line with the exact sum of the n integers, in decimal, with a minus sign when it is negative.
Constraints. 1 <= n <= 40000. Each integer is between -1000000000000000000 and 1000000000000000000, which is 1018.
Sample. Input 3 and 9007199254740991 9007199254740991 1 gives 18014398509481983.
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, then n integers. Print their exact sum: BigInt, not Number.
console.log(out.join("\n"));
Run in Compiler
Hint 1
1018 is far above 253. What happens to 9007199254740993 inside nextInt()?
Hint 2
Start the sum at 0n, and add BigInt(next()) for each token. Push String(sum).
Common doubts
My answer is 0.30000000000000004 and I know it means 0.3. Why does the judge not round it for me?
The judge compares text, and it cannot know which digits you meant. The statement says what to print, and here it says "as JavaScript prints it". So the expected line holds all 17 digits, and printing
0.3would be the wrong answer.Can I use Math.max in largest-of-three?
The judge sees only your output, so it would pass. But the problem exists to train the ternary operator, and the statement asks for it. Kenji's
Math.maxis the right tool in real code; here it skips the exercise.Why do two problems need the lines variant? I could skip empty tokens.
That is the problem. The token split drops empty lines, because
.filter(Boolean)removes every empty string. An empty field then vanishes, and every later field moves up by one. The lines variant keeps each line, empty or not, as one value.Why not use BigInt everywhere, to be safe?
A bigint holds only whole numbers:
BigInt("3.5")throwsSyntaxError: Cannot convert 3.5 to a BigInt. It does not mix with numbers in arithmetic, andMath.max(1n, 2n)throwsTypeError: Cannot convert a BigInt value to a number. Use it where a total can pass 253, and nowhere else.My program passes the sample. Why does a hidden test fail?
The sample is one small case, chosen to explain the statement. The hidden tests add
-0,NaN,Infinity, empty lines and the largest sizes. The table of edges above names them; run the small ones on the Playground before you submit.
Key takeaways
- Read a number with
nextInt(), text withnext(), an exact big integer withBigInt(next()), and a line that may be empty with the lines variant. - The judge compares text, and every number leaves through
String():-0prints0, and0.1 + 0.2prints0.30000000000000004. - Settle each value's type before an operator touches it:
+joins as soon as one side is a string. ??keeps""and0,== nullcatchesnullandundefined, andObject.istellsNaNand-0apart.- Test the edges before the sample:
-0,NaN,Infinity, an empty line and the largest safe integer. - Go deeper: Interview Pack, output puzzles, the questions and the bug gallery (Pro).
Next comes the module test: ten questions and two of these problems, calculator and clean-numbers. After it, the cheat sheet puts the whole module on one page, and Module 3 opens strings.
End of lesson 7
Get every problem accepted, and the lesson is done.
0 of 3 free problems accepted
Next: Cheat Sheet: Types, Operators and Coercion on One Page