多重ループ

ループの中にループを入れる

一つのループの中に、さらにループを入れることができます。 もちろん入れ子の深さを二重、三重、...と深くしていくことも可能です。 これらをまとめて多重ループと呼びます。 多重ループでは、for文、while文、do〜while文などのあらゆる種類のループの組み合わせが考えられます。

ここでは、for文による二重ループを使って、算数でおなじみの九九の表を表示するプログラムを作ってみましょう。

MultipleLoopSample01.java
class MultipleLoopSample01 {
    public static void main(String[] args) {
        for(int i = 1; i <= 9; i++){
            for(int j = 1; j <= 9; j++){
                System.out.print(" " + i * j);
            }
            System.out.println();
        }
    }
}

今回は実行結果をスクリーンショットで見てみましょう。 これはMacのターミナルによる実行結果です。

図 7-4 : MultipleLoopSample01の実行結果

確かに九九の表が表示されました。 この表は上の方から一の段、二の段、...、九の段というように順に並んでいます。 たったこれだけのコードで九九の表ができてしまうなんて、多重ループというのはとても強力なものですね。

MultipleLoopSample01の外側のfor文では、変数iの値を1から9までインクリメントしていきます。 これは、九九の表の1行目(一の段)から9行目(九の段)までに対応しています。 言わば行ループです。 そして、内側のfor文では、変数jの値を1から9までインクリメントしていきます。 これは、九九の表のi行目の中の1列目から9列目までに対応しています。 こちらは列ループと言うことになります。

例えば、行ループでiの値が6のときは、列ループでjの値が1, 2, 3, ..., 9とインクリメントされていく間、六の段が順に表示されていくことになります。 実際に数字を表示しているのは次の部分です。

                System.out.print(" " + i * j);

数字の左にスペースを入れて、となりの数字との間に隙間を開けています。

列ループが終了したとき、つまり、一つの段が終わったときに、

            System.out.println();

を実行して、改行しています。 こうしないと、すべての段がつながって、1行に表示されてしまいます。 print は改行しないことに注意してください。

表 7-5 : MultipleLoopSample01でのfor文の流れ
行ループでの
iの値
列ループでの処理 表示内容
1 jを1から9までインクリメントしながら1 * jを表示 一の段
2 jを1から9までインクリメントしながら2 * jを表示 二の段
3 jを1から9までインクリメントしながら3 * jを表示 三の段
4 jを1から9までインクリメントしながら4 * jを表示 四の段
5 jを1から9までインクリメントしながら5 * jを表示 五の段
6 jを1から9までインクリメントしながら6 * jを表示 六の段
7 jを1から9までインクリメントしながら7 * jを表示 七の段
8 jを1から9までインクリメントしながら8 * jを表示 八の段
9 jを1から9までインクリメントしながら9 * jを表示 九の段

ところで、MultipleLoopSample01の実行結果では、縦の列が揃っていないため、読みにくく見栄えも良く有りませんね。 そこで、縦の列がそろうように改良したものが次のMultipleLoopSample01Aです。 なお、ここで登場する printf というメソッドはJava5.0以降でのみ利用可能です。

MultipleLoopSample01A.java
class MultipleLoopSample01A {
    public static void main(String[] args) {
        for(int i = 1; i <= 9; i++){
            for(int j = 1; j <= 9; j++){
                System.out.printf(" %2d", i * j);
            }
            System.out.println();
        }
    }
}
図 7-5 : MultipleLoopSample01Aの実行結果

簡単に解決してしまいましたね。 変更箇所はたった一つ、

                System.out.printf(" %2d", i * j);

の部分だけです。 " %2d"という文字列の1文字目は半角のスペースになっていて、これはそのまま表示されます。 %2d は書式文字列と呼ばれる部分です。 このように書式を指定すると、カンマ(,)の後の整数値を少なくても2桁の幅で、10進数として右詰めで表示してくれます。 % は書式文字列の始まりを示し、 d は10進数を意味します。

図 7-6 : 書式文字列

繰り返しの回数を変化させる

さて、次は入力された行数だけ*(アスタリスク)を表示するプログラムを作ってみましょう。 ただし、1行目は*を1個、2行目は2個、...、n行目はn個というルールで表示させます。 これはForSample02の発展形と言えるものです。

MultipleLoopSample02.java
import java.io.*;

class MultipleLoopSample02 {
    public static void main(String[] args) throws IOException{
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        
        System.out.println("*を何行表示しますか。");
        int num = Integer.parseInt(br.readLine());
        
        for(int i = 1; i <= num; i++){
            for(int j = 1; j <= i; j++){
                System.out.print("*"); //アスタリスクを表示するが、改行しない。
            }
            System.out.println(); //列ループが終了したので、改行する。
        }        
    }
}
MultipleLoopSample02の実行結果
*を何行表示しますか。
5
*
**
***
****
*****

MultipleLoopSample01(九九の表)では、行ループも列ループも繰り返しの回数は9回と決まっていました。

MultipleLoopSample02の行ループでは、繰り返しの条件が i <= num となっているため、入力された回数だけループ本体が実行されます。 また、列ループでは、繰り返しの条件が j <= i となっているため、1行目は1回、2行目は2回、...、num行目はnum回というように、繰り返しの回数が多くなっていきます。 その結果、1行目は*が1個、2行目は2個、...、num行目はnum個というように表示されていきます。

MultipleLoopSample02で「5」を入力した場合のfor文の流れは表 7-6のようになります。

表 7-6 : MultipleLoopSample02でのfor文の流れ(5行目まで表示)
行ループでの
iの値
列ループでの処理 表示内容
1 jを1から1までインクリメントしながら*を表示 *
2 jを1から2までインクリメントしながら*を表示 **
3 jを1から3までインクリメントしながら*を表示 ***
4 jを1から4までインクリメントしながら*を表示 ****
5 jを1から5までインクリメントしながら*を表示 *****

ループの中にループを入れていけば、二重、三重の繰り返し処理が実現できる。