8.ネストしたループ
学習目標
- ループの中にループを書いて、2重の繰り返し処理を実行できる
- ネストしたループの実行順序をトレースできる
1. ネストしたループ
Section titled “1. ネストしたループ”「1 から 3 までの数の組み合わせをすべて出力する」プログラムを考えます。(1,1), (1,2), (1,3), (2,1), … , (3,3) の 9 通りです。
1つの for ループで扱える変数は1つだけです。2つの変数を組み合わせるには、ループの中にもう1つのループを入れます。これを ネストしたループ(入れ子のループ)と呼びます。
1-1. 基本の書き方
Section titled “1-1. 基本の書き方”for (let i = 1; i <= 3; i++) { for (let j = 1; j <= 3; j++) { console.log(i + "," + j); }}1,11,21,32,12,22,33,13,23,3外側のループでは i が 1, 2, 3 と進みます。i が 1 つの値を取っているあいだに、内側のループで j が 1, 2, 3 と進みます。内側のループが終わると外側に戻り、i が次の値になって、内側のループがまた j = 1 から始まります。
1-2. 実行順序のトレース
Section titled “1-2. 実行順序のトレース”外側と内側の変数がどう進むかを 1 ステップずつ追います。
i | j | 出力 |
|---|---|---|
| 1 | 1 | 1,1 |
| 1 | 2 | 1,2 |
| 1 | 3 | 1,3 |
| 2 | 1 | 2,1 |
| 2 | 2 | 2,2 |
| 2 | 3 | 2,3 |
| 3 | 1 | 3,1 |
| 3 | 2 | 3,2 |
| 3 | 3 | 3,3 |
i の値ごとに j が 3 回動くので、全部で 3 × 3 = 9 回の出力になります。
2. 九九の表
Section titled “2. 九九の表”ネストしたループの典型的な例が九九の表です。
2-1. 基本の書き方
Section titled “2-1. 基本の書き方”for (let i = 1; i <= 9; i++) { let line = "";
for (let j = 1; j <= 9; j++) { line = line + (i * j) + "\t"; }
console.log(line);}1 2 3 4 5 6 7 8 92 4 6 8 10 12 14 16 183 6 9 12 15 18 21 24 274 8 12 16 20 24 28 32 365 10 15 20 25 30 35 40 456 12 18 24 30 36 42 48 547 14 21 28 35 42 49 56 638 16 24 32 40 48 56 64 729 18 27 36 45 54 63 72 81外側の i が段(行)、内側の j が列を表しています。"\t" はタブ文字で、値の間にスペースを空けるために使っています。
2-2. 1 行分の組み立て
Section titled “2-2. 1 行分の組み立て”let line = "" を外側のループの中に書くことで、行ごとに空文字列から始めます。外側のループが 1 周するたびに line がリセットされ、1 行分の文字列が新しく組み立てられます。
i = 1 のとき、内側のループで line がどう変化するかを追います。
j | i * j | line |
|---|---|---|
| 1 | 1 | "1\t" |
| 2 | 2 | "1\t2\t" |
| 3 | 3 | "1\t2\t3\t" |
| … | … | … |
| 9 | 9 | "1\t2\t3\t4\t5\t6\t7\t8\t9\t" |
内側のループが終わった時点で、console.log(line) が 1 行分をまとめて出力します。外側のループの次の周回では、line が再び空文字列にリセットされ、2 行目が組み立てられます。
3. ネストしたループと配列
Section titled “3. ネストしたループと配列”ネストしたループは、配列の要素同士をすべての組み合わせで比較するときにも使います。この「すべてのペアを比較する」パターンは ソートアルゴリズム でも使います。
3-1. ペアの列挙
Section titled “3-1. ペアの列挙”const data = [3, 1, 4];
for (let i = 0; i < data.length; i++) { for (let j = i + 1; j < data.length; j++) { console.log(data[i] + " と " + data[j]); }}3 と 13 と 41 と 4出力されるペアは (3, 1), (3, 4), (1, 4) の 3 通りです。自分自身との比較や、順序を入れ替えただけのペアは含まれません。
3-2. 内側ループの開始位置
Section titled “3-2. 内側ループの開始位置”内側のループが j = i + 1 から始まっているのがポイントです。j = 0 から始めると、同じペアが 2 回出力されたり、自分自身と比較したりしてしまいます。j = i + 1 にすることで、まだ比較していないペアだけを処理します。
各 i について、内側のループがどの j を取るかをトレースします。
i | data[i] | j が取る値 | 出力されるペア |
|---|---|---|---|
| 0 | 3 | 1, 2 | 3 と 1, 3 と 4 |
| 1 | 1 | 2 | 1 と 4 |
| 2 | 4 | (なし) | — |
i = 2 のとき、内側のループの初期値は j = i + 1 = 3 ですが、条件式 j < data.length は 3 < 3 で false になり、内側のループは 1 度も実行されません。配列の最後の要素には、比較相手が残っていないためです。