paizaの「整数を半角 + 改行区切りで入力 3」という問題に取り組みました。
今回の問題では、10個の整数が4行に分かれて入力されます。
各整数に 1 を足し、改行区切りで出力します。
問題
入力は次の形式で与えられます。
p_1 p_2
p_3 p_4
e_1 e_2 e_3 e_4
a b
それぞれの整数に 1 を足して、10行で出力します。
入力例
4 9
2 1
0 0 9 0
6 5
出力例
5
10
3
2
1
1
10
1
7
6
書いたコード
process.stdin.resume();
process.stdin.setEncoding("utf8");
var lines = [];
var reader = require("readline").createInterface({
input: process.stdin,
output: process.stdout,
});
reader.on("line", (line) => {
lines.push(line);
});
reader.on("close", () => {
const input1 = lines[0].split(" ").map(Number);
const input2 = lines[1].split(" ").map(Number);
const input3 = lines[2].split(" ").map(Number);
const input4 = lines[3].split(" ").map(Number);
const p_1 = input1[0];
const p_2 = input1[1];
const p_3 = input2[0];
const p_4 = input2[1];
const e_1 = input3[0];
const e_2 = input3[1];
const e_3 = input3[2];
const e_4 = input3[3];
const a = input4[0];
const b = input4[1];
console.log(p_1 + 1);
console.log(p_2 + 1);
console.log(p_3 + 1);
console.log(p_4 + 1);
console.log(e_1 + 1);
console.log(e_2 + 1);
console.log(e_3 + 1);
console.log(e_4 + 1);
console.log(a + 1);
console.log(b + 1);
});
このコードで正しく出力できます。
入力がどのように保存されるか
入力が次の場合を考えます。
4 9
2 1
0 0 9 0
6 5
readlineで1行ずつ受け取り、linesに追加しているため、配列の中身は次のようになります。
lines[0]; // "4 9"
lines[1]; // "2 1"
lines[2]; // "0 0 9 0"
lines[3]; // "6 5"
標準入力から受け取った値は、数値ではなく文字列です。
また、各行には複数の整数が半角スペース区切りで入っています。
そのため、各行に対して次の処理を行います。
lines[0].split(" ").map(Number);
split(" ")で半角スペースごとに分ける
split(" ")は、文字列を半角スペースの位置で分割します。
たとえば、次の文字列に対して、
"4 9"
split(" ")を使うと、
"4 9".split(" ");
次の配列になります。
["4", "9"]
ただし、この時点では配列の中身は文字列です。
map(Number)で数値に変換する
map(Number)を使うと、配列の中にあるすべての文字列を数値へ変換できます。
["4", "9"].map(Number);
結果は次のようになります。
[4, 9]
そのため、次の処理では、
const input1 = lines[0].split(" ").map(Number);
半角スペースで分ける処理と、数値に変換する処理をまとめて行っています。
各行の変換結果
入力例の場合、各変数の中身は次のようになります。
const input1 = lines[0].split(" ").map(Number);
// [4, 9]
const input2 = lines[1].split(" ").map(Number);
// [2, 1]
const input3 = lines[2].split(" ").map(Number);
// [0, 0, 9, 0]
const input4 = lines[3].split(" ").map(Number);
// [6, 5]
配列から値を取り出す
配列の中の値は、添字を使って取り出します。
const p_1 = input1[0];
const p_2 = input1[1];
input1の中身が次の場合、
[4, 9]
それぞれの値は次のようになります。
input1[0]; // 4
input1[1]; // 9
配列の添字は 0 から始まる点に注意します。
今回の入力と変数の対応は次のとおりです。
const p_1 = input1[0];
const p_2 = input1[1];
const p_3 = input2[0];
const p_4 = input2[1];
const e_1 = input3[0];
const e_2 = input3[1];
const e_3 = input3[2];
const e_4 = input3[3];
const a = input4[0];
const b = input4[1];
各整数に1を足して出力する
最後に、各整数に 1 を足して出力します。
console.log(p_1 + 1);
console.log(p_2 + 1);
console.log()を1回実行するごとに改行されるため、10回書くことで10行に分けて出力できます。
console.log(p_1 + 1);
console.log(p_2 + 1);
console.log(p_3 + 1);
console.log(p_4 + 1);
console.log(e_1 + 1);
console.log(e_2 + 1);
console.log(e_3 + 1);
console.log(e_4 + 1);
console.log(a + 1);
console.log(b + 1);
処理の流れ
今回のコードは、次の順番で処理しています。
- 入力を1行ずつ
linesに保存する - 各行を半角スペースで分割する
-
map(Number)で文字列を数値へ変換する - 配列からそれぞれの値を取り出す
- 各整数に
1を足して出力する
コードでは次の部分が、半角スペースでの分割と数値への変換を行っています。
const input1 = lines[0].split(" ").map(Number);
別の書き方1:分割代入を使う
配列から値を取り出すときは、分割代入を使うこともできます。
reader.on("close", () => {
const [p_1, p_2] = lines[0].split(" ").map(Number);
const [p_3, p_4] = lines[1].split(" ").map(Number);
const [e_1, e_2, e_3, e_4] = lines[2].split(" ").map(Number);
const [a, b] = lines[3].split(" ").map(Number);
console.log(p_1 + 1);
console.log(p_2 + 1);
console.log(p_3 + 1);
console.log(p_4 + 1);
console.log(e_1 + 1);
console.log(e_2 + 1);
console.log(e_3 + 1);
console.log(e_4 + 1);
console.log(a + 1);
console.log(b + 1);
});
たとえば、次のコードでは、
const [p_1, p_2] = [4, 9];
配列の値が順番に変数へ代入されます。
p_1; // 4
p_2; // 9
元のコードでは、次のように1つずつ取り出していました。
const p_1 = input1[0];
const p_2 = input1[1];
分割代入を使うと短く書けますが、まだ慣れていない場合は、元の書き方のほうが処理を追いやすいと思います。
別の書き方2:すべての整数を1つの配列にまとめる
今回の問題では、すべての整数に同じように 1 を足します。
そのため、変数を1つずつ作らず、すべての整数を1つの配列にまとめて処理する方法もあります。
process.stdin.resume();
process.stdin.setEncoding("utf8");
var lines = [];
var reader = require("readline").createInterface({
input: process.stdin,
output: process.stdout,
});
reader.on("line", (line) => {
lines.push(line);
});
reader.on("close", () => {
const numbers = lines.join(" ").split(" ").map(Number);
for (let i = 0; i < numbers.length; i++) {
console.log(numbers[i] + 1);
}
});
join(" ")とは
linesの中身は次のようになっています。
["4 9", "2 1", "0 0 9 0", "6 5"]
join(" ")を使うと、配列の要素を半角スペースでつなげられます。
lines.join(" ");
結果は次の文字列になります。
4 9 2 1 0 0 9 0 6 5
その後、再びsplit(" ")で分割し、map(Number)で数値に変換します。
const numbers = lines.join(" ").split(" ").map(Number);
結果は次の配列になります。
[4, 9, 2, 1, 0, 0, 9, 0, 6, 5]
あとはfor文を使い、すべての要素に 1 を足して出力します。
for (let i = 0; i < numbers.length; i++) {
console.log(numbers[i] + 1);
}
この方法は、同じ処理を何度も書かなくてよい点が便利です。
別の書き方3:出力する値を配列にしてまとめる
各整数に 1 を足した結果を配列にし、join("\n")で改行区切りにする方法もあります。
reader.on("close", () => {
const numbers = lines.join(" ").split(" ").map(Number);
const answers = [];
for (let i = 0; i < numbers.length; i++) {
answers.push(numbers[i] + 1);
}
console.log(answers.join("\n"));
});
answersには、各整数に 1 を足した結果を追加しています。
answers.push(numbers[i] + 1);
入力例の場合、最終的なanswersは次のようになります。
[5, 10, 3, 2, 1, 1, 10, 1, 7, 6]
join("\n")を使うと、配列の値を改行でつなげられます。
answers.join("\n");
出力結果は次のようになります。
5
10
3
2
1
1
10
1
7
6
どの書き方が分かりやすいか
今回最初に書いたコードは、どの入力がどの変数に入っているのかが分かりやすいです。
const p_1 = input1[0];
const p_2 = input1[1];
少し長くなりますが、配列の添字や入力の位置を確認しながら書けます。
一方で、今回のようにすべての整数へ同じ処理をする場合は、配列とfor文を使うと短く書けます。
const numbers = lines.join(" ").split(" ").map(Number);
for (let i = 0; i < numbers.length; i++) {
console.log(numbers[i] + 1);
}
まずは最初のコードで、入力の分割や配列から値を取り出す流れを理解し、慣れてきたらfor文を使う方法に挑戦するとよさそうです。
まとめ
今回のポイントは、半角スペース区切りの入力を数値の配列へ変換することです。
const input1 = lines[0].split(" ").map(Number);
この1行では、次の2つの処理を行っています。
split(" ");
半角スペースごとに文字列を分割します。
map(Number);
分割したすべての文字列を数値へ変換します。
また、配列の値は添字を使って取り出せます。
const p_1 = input1[0];
const p_2 = input1[1];
今回のように同じ計算を複数の値へ行う問題では、慣れてきたら配列とfor文を使うことで、より短く書けることも覚えておきたいです。