Java超|配列とループでデータを処理する

配列はデータを並べる棚、ループはその棚を順番に見ていく巡回ルート。
この2つを組み合わせると、たくさんのデータを1つずつ安全に、効率よく処理できる。

配列は、同じ型のデータをまとめて並べておける仕組みです。

たとえば、戦士たちの修行歩数、身長、点数、戦闘力、任務達成数のように、同じ種類の値がいくつもある場面では、配列を使うとデータを整理しやすくなります。

ただし、配列の便利さが本当に見えてくるのは、ループと組み合わせたときです。

配列には、0、1、2、3 のような添字が順番に付いています。
そして、for文のループ変数も、0、1、2、3 のように順番に変化させられます。

つまり、配列の添字とfor文のループ変数は、とても相性がよいのです。

仕組み役割
配列同じ型のデータを番号付きで並べる
ループ同じ処理を繰り返す
配列 + ループ並んだデータを先頭から順番に処理する

ドラゴンボール風にたとえると、配列は「戦士たちの修行記録札が番号順に並んだ訓練棚」です。

0番の札には1日目の修行歩数。
1番の札には2日目の修行歩数。
2番の札には3日目の修行歩数。

このように、記録札が順番に並んでいます。

そして、for文はその棚を 0番、1番、2番……と順番に確認していく巡回ルートです。

戦士が記録棚の前を歩きながら、0番の札、1番の札、2番の札を順番に確認していく。
これが、配列とループを組み合わせる基本イメージです。

この記事では、配列とループを組み合わせるとコードがどのように整理されるのか、ループ変数を添字として使うとはどういうことか、配列の範囲を超えないために何に注意するのかを、Sample1.java と Sample2.java を使って整理していきます。

配列とループはとても相性がよい

配列の各要素には、添字という番号が付いています。

Javaの配列では、最初の添字は 0 です。
そこから 1、2、3、4……と順番に続きます。

たとえば、5個の要素を持つ配列なら、使える添字は次のようになります。

要素の順番添字
1個目0
2個目1
3個目2
4個目3
5個目4

一方、for文では、ループ変数を 0 から始めて、1ずつ増やしながら処理できます。

for(int i = 0; i < 5; i++){
    処理
}

この形では、i の値は次のように変化します。

0, 1, 2, 3, 4

これは、5個の要素を持つ配列の添字とぴったり対応します。

ループ回数i の値対応する配列要素
1回目0data[0]
2回目1data[1]
3回目2data[2]
4回目3data[3]
5回目4data[4]

ドラゴンボール風にたとえると、i は「訓練記録棚を確認する巡回番号」です。

i が 0 のときは、0番の記録札を見る。
i が 1 のときは、1番の記録札を見る。
i が 2 のときは、2番の記録札を見る。

このように、ループ変数を添字として使うことで、配列の要素を先頭から順番に処理できます。

ループを使わないと同じ処理が増えてしまう

配列の要素を1つずつ表示するだけなら、添字を直接指定して書くこともできます。

System.out.println(data[0]);
System.out.println(data[1]);
System.out.println(data[2]);
System.out.println(data[3]);
System.out.println(data[4]);

5個くらいなら、まだ書けそうに見えるかもしれません。

しかし、要素数が20個、50個、100個になったらどうでしょうか。

同じような文を何十行も書くことになります。
さらに、途中で data[17] を書き忘れたり、番号を間違えたりする可能性も高くなります。

そこで、for文を使います。

for(int i = 0; i < 5; i++){
    System.out.println(data[i]);
}

このように書けば、i が 0 から 4 まで変化し、data[0] から data[4] までを順番に表示できます。

書き方特徴
添字を直接書く要素数が少ないときは見えるが、数が増えると大変
ループを使う要素数が増えても同じ形で処理しやすい

配列とループを組み合わせると、同じような処理を何度も書かなくて済みます。

これは、コードを短くするだけではありません。
添字の書き間違いや、処理の抜け漏れを減らすことにもつながります。

ドラゴンボール風にたとえると、記録札を1枚ずつ手作業で探して読むより、巡回ルートを決めて順番に確認したほうが安全です。

0番から4番までを順番に見ると決めておけば、見落としが少なくなります。

なぜ配列とループを組み合わせると便利なのか

配列とループには、それぞれ役割があります。

仕組み役割
配列同じ型のデータを順番に並べて保存する
ループ同じ処理を繰り返す
配列 + ループ並んだデータを順番にまとめて処理する

配列だけでは、データをまとめて保存できます。

ループだけでは、同じ処理を繰り返せます。

この2つを組み合わせると、たくさんのデータを順番に処理できるようになります。

たとえば、次のような処理に向いています。

処理配列とループの役割
全要素を表示する添字を順番に変えながら表示する
合計を求める各要素を順番に足していく
平均を求める合計を求めて、要素数で割る
最大値を探す1つずつ比較する
条件に合う値を探すループで順番に確認する

ドラゴンボール風にたとえると、配列は「戦士たちの記録札を並べた棚」です。
ループは「その棚を順番に巡回する足運び」です。

記録札が整列しているからこそ、巡回しながら確認できます。
巡回の動きがあるからこそ、すべての記録を一括で処理できます。

つまり、配列とループは、データをまとめて扱うための強力なコンビです。

図:ループ変数で配列の要素を順番に取り出す

この図が示していること

この図では、for文のループ変数 i が 0 から 4 まで変化し、それに合わせて steps[0] から steps[4] までを順番に取り出す様子を示しています。

i が 0 のときは steps[0] を扱います。
i が 1 のときは steps[1] を扱います。
i が 2 のときは steps[2] を扱います。

つまり、ループが1回進むごとに、配列の次の要素へ移動しているわけです。

ここから分かることは、配列とループを組み合わせると、要素を1つずつ手で指定しなくても、順番にまとめて処理できるということです。

配列の値を順番に表示する

まずは、配列とループの基本的な組み合わせを確認します。

ここでは、5日分の修行歩数を配列に入れて、順番に表示します。

ファイル名:Sample1.java

class Sample1
{
    public static void main(String[] args)
    {
        int[] steps;
        steps = new int[5];   // 5日分の修行歩数を入れる配列を準備する

        steps[0] = 3200;
        steps[1] = 5400;
        steps[2] = 6100;
        steps[3] = 4500;
        steps[4] = 7000;   // 各要素に修行歩数を代入する

        for(int i = 0; i < 5; i++){
            System.out.println((i + 1) + "日目の修行歩数は " +
                               steps[i] + " 歩です。");
        }   // ループを使って順番に表示する
    }
}

実行結果は次のようになります。

1日目の修行歩数は 3200 歩です。
2日目の修行歩数は 5400 歩です。
3日目の修行歩数は 6100 歩です。
4日目の修行歩数は 4500 歩です。
5日目の修行歩数は 7000 歩です。

このプログラムでは、まず steps という配列を用意しています。

int[] steps;
steps = new int[5];

これで、整数を5個入れられる配列ができます。

そのあと、5つの要素に修行歩数を代入しています。

添字代入される値
03200
15400
26100
34500
47000

最後に、for文を使って steps[0] から steps[4] までを順番に表示しています。

for(int i = 0; i < 5; i++){
    System.out.println((i + 1) + "日目の修行歩数は " +
                       steps[i] + " 歩です。");
}

ここで大切なのは、steps[i] です。

配列の添字に、直接 0 や 1 を書くのではなく、ループ変数 i を使っています。

ループの中で添字に変数を使う

Sample1.java で特に大切なのは、次の部分です。

steps[i]

配列の添字には、数字を直接書くだけでなく、変数も使えます。

for文では、i が 0、1、2、3、4 と変化します。
そのため、steps[i] は、ループのたびに次のように意味が変わります。

ループ回数i の値steps[i] の意味取り出される値
1回目0steps[0]3200
2回目1steps[1]5400
3回目2steps[2]6100
4回目3steps[3]4500
5回目4steps[4]7000

このように、ループ変数 i を添字として使うことで、配列の要素を先頭から順番に取り出せます。

ドラゴンボール風にたとえると、i は訓練記録パネルを巡回する番号です。

i が 0 のときは0番の記録札。
i が 1 のときは1番の記録札。
i が 2 のときは2番の記録札。

この仕組みが分かると、配列の中にたくさんの値があっても、同じ形の処理で順番に扱える理由が見えてきます。

表示では i + 1 を使っている

Sample1.java では、表示部分に i + 1 が使われています。

System.out.println((i + 1) + "日目の修行歩数は " +
                   steps[i] + " 歩です。");

これは、配列の添字と、人間が見る日数の数え方が違うからです。

配列の添字は 0 から始まります。
でも、画面に表示するときは、1日目、2日目、3日目 のように見せたいです。

i の値配列の要素表示したい日数
0steps[0]1日目
1steps[1]2日目
2steps[2]3日目
3steps[3]4日目
4steps[4]5日目

そのため、表示上の日数には i + 1 を使っています。

ここは、配列とループを組み合わせるときによく出てきます。

内部では0から数える。
人に見せるときは1から数える。

この違いを意識しておくと、表示のズレを防ぎやすくなります。

ドラゴンボール風にたとえると、訓練記録パネルの内部番号は0番から始まります。
でも、戦士に結果を伝えるときは「1日目」「2日目」と表示したほうが自然です。

配列の大きさを超えてはいけない

配列を使うときに、とても大事な注意点があります。

それは、用意した要素数を超える添字は使えないということです。

たとえば、5個の要素を持つ配列を作った場合、使える添字は 0 から 4 までです。

要素数使える添字
50, 1, 2, 3, 4

この場合、steps[0] から steps[4] までは存在します。

しかし、steps[5] や steps[8] は存在しません。

指定存在するか
steps[0]存在する
steps[1]存在する
steps[2]存在する
steps[3]存在する
steps[4]存在する
steps[5]存在しない
steps[8]存在しない

ドラゴンボール風にたとえると、0番から4番までしかない訓練記録棚で、8番の記録札を開こうとしている状態です。

その記録札は、そもそも存在しません。

配列では、存在しない場所を指定して値を入れたり、値を取り出したりすることはできません。
そのため、ループを書くときには、配列の範囲を超えないように条件を正しく書く必要があります。

添字の範囲を間違えないための考え方

添字の範囲で迷ったときは、次のルールを思い出しましょう。

ルール内容
最初の添字0
最後の添字要素数 - 1

たとえば、要素数が 5 なら、最後の添字は 4 です。
要素数が 10 なら、最後の添字は 9 です。

要素数最後の添字
32
54
87
109

このルールは、for文の条件を書くときにも重要です。

5個の要素を順番に処理するなら、次のように書きます。

for(int i = 0; i < 5; i++){
    処理
}

この場合、i は 0、1、2、3、4 まで変化します。

i が 5 になると、条件 i < 5 が false になるため、ループは止まります。

i の値i < 5処理されるか
0true処理される
1true処理される
2true処理される
3true処理される
4true処理される
5false処理されない

この形なら、存在する添字 0 から 4 だけを扱えます。
そのため、配列の範囲を超えません。

ドラゴンボール風にたとえると、巡回担当の戦士が0番から4番までの記録札だけを確認し、5番には進まないようにしている状態です。

図:配列の範囲を超える添字は使えない

この図が示していること

この図では、steps 配列に存在する要素が 0 から 4 までであることを示しています。

steps[0]、steps[1]、steps[2]、steps[3]、steps[4] は存在します。
しかし、steps[5] や steps[8] は存在しません。

ここから分かることは、配列は決められた数の箱を持つ仕組みであり、好きな添字を自由に使えるわけではないということです。

配列とループを組み合わせるときは、ループ変数が配列の範囲内に収まるように条件を書く必要があります。

要素数があらかじめ分からない場合もある

ここまでの例では、配列の要素数を 5 と決めていました。

しかし、実際のプログラムでは、最初から必要な要素数が分からないこともあります。

たとえば、次のような場面です。

場面必要な要素数
何人分の身長を記録するか使う人が決める
何日分の修行記録を扱うか入力内容によって変わる
何個の買い物金額を登録するかその場で変わる
何人の戦士の点数を入力するか実行時に決まる

このような場合は、先に個数を入力してもらい、その数に合わせて配列を作ると便利です。

ドラゴンボール風にたとえると、訓練に参加する戦士の人数は日によって変わります。

4人の日もあれば、10人の日もあります。
その場合、最初に人数を確認して、その人数分だけ記録棚の枠を用意するほうが自然です。

入力された数だけ配列を作る

次に、人数を入力して、その人数分の身長を配列に保存し、最後に順番に表示するプログラムを見ていきます。

ファイル名:Sample2.java

import java.io.*;

class Sample2
{
    public static void main(String[] args) throws IOException
    {
        System.out.println("記録する戦士の人数を入力してください。");

        BufferedReader br =
            new BufferedReader(new InputStreamReader(System.in));

        String str = br.readLine();
        int num = Integer.parseInt(str);   // 配列の要素数を入力する

        int[] height;
        height = new int[num];   // 入力された人数分だけ配列を準備する

        System.out.println("戦士の人数分、身長を入力してください。");

        for(int i = 0; i < num; i++){
            str = br.readLine();   // 1人分ずつ身長を入力する
            int tmp = Integer.parseInt(str);
            height[i] = tmp;   // 入力した身長を配列に保存する
        }

        for(int i = 0; i < num; i++){
            System.out.println((i + 1) + "人目の戦士の身長は " +
                               height[i] + " cmです。");   // 保存した身長を表示する
        }
    }
}

実行結果は次のようになります。

記録する戦士の人数を入力してください。
4
戦士の人数分、身長を入力してください。
165
172
158
180
1人目の戦士の身長は 165 cmです。
2人目の戦士の身長は 172 cmです。
3人目の戦士の身長は 158 cmです。
4人目の戦士の身長は 180 cmです。

このプログラムでは、最初に記録する戦士の人数を入力してもらいます。

int num = Integer.parseInt(str);

そして、その num を使って配列を作っています。

height = new int[num];

これにより、入力された人数に合わせた大きさの配列が作られます。

入力された人数 num作られる配列
3int型の要素を3個持つ配列
4int型の要素を4個持つ配列
10int型の要素を10個持つ配列

固定で5個や10個にするのではなく、実行時に入力された人数に合わせて配列の大きさを決めています。

ドラゴンボール風にたとえると、まず「今日の訓練に参加する戦士は何人か」を確認します。
その人数に合わせて、身長記録用の枠を作るイメージです。

Sample2.javaの流れを整理する

Sample2.java の流れは、次のように整理できます。

順番処理
1記録する人数を入力する
2入力された人数を num に入れる
3num 個分の要素を持つ配列 height を作る
4for文で人数分の身長を入力する
5入力された身長を height[i] に保存する
6もう一度for文で全員分の身長を表示する

ここで大切なのは、配列の大きさとループの回数が、どちらも num によって決まっていることです。

height = new int[num];

for(int i = 0; i < num; i++){
    処理
}

このようにすると、入力された人数、配列の要素数、ループの回数がそろいます。

num の値height の要素数i の変化処理回数
33個0, 1, 23回
44個0, 1, 2, 34回
55個0, 1, 2, 3, 45回

ドラゴンボール風にたとえると、最初に「今日の訓練参加者は何人か」を確認します。
その人数分だけ身長記録の枠を作ります。
そして、0番から順番に身長を記録し、あとで同じ順番で読み上げます。

入力用のループと表示用のループ

Sample2.java では、for文が2回出てきます。

1つ目のfor文は、身長を入力して配列に保存するためのループです。

for(int i = 0; i < num; i++){
    str = br.readLine();   // 1人分ずつ身長を入力する
    int tmp = Integer.parseInt(str);
    height[i] = tmp;   // 入力した身長を配列に保存する
}

2つ目のfor文は、保存した身長を表示するためのループです。

for(int i = 0; i < num; i++){
    System.out.println((i + 1) + "人目の戦士の身長は " +
                       height[i] + " cmです。");   // 保存した身長を表示する
}
ループ役割
1つ目のfor文入力された値を配列に保存する
2つ目のfor文配列に保存された値を順番に表示する

どちらのループでも、i は 0 から num - 1 まで変化します。

つまり、配列の範囲内だけを順番に扱っています。

ドラゴンボール風にたとえると、1回目の巡回では、戦士たちの身長を記録札に書き込んでいきます。
2回目の巡回では、その記録札を順番に読み上げていきます。

同じ記録棚を、目的を変えて2回巡回しているイメージです。

ループ条件にも配列の大きさを使う

Sample2.java では、for文の条件に num を使っています。

for(int i = 0; i < num; i++)

これはとても重要です。

num は、配列の要素数を決める値です。

そのため、ループ条件にも num を使うことで、配列の大きさに合った回数だけ処理できます。

num の値i の変化処理回数
30, 1, 23回
40, 1, 2, 34回
50, 1, 2, 3, 45回

もし配列の大きさが num で決まっているのに、ループ条件を固定の数にしてしまうと、入力人数と合わなくなることがあります。

たとえば、num が 4 なのに、ループが10回まわると、存在しない要素にアクセスしてしまう可能性があります。

反対に、num が 10 なのに、ループが4回しかまわらないと、残りの要素を処理できません。

状態起きる問題
配列は4個なのに10回ループする5個目以降の存在しない要素に進む危険がある
配列は10個なのに4回しかループしない5個目以降の要素を処理できない
配列の要素数とループ回数が同じ範囲内で安全に処理しやすい

だから、配列の大きさが入力で決まる場合は、配列作成とループ条件に同じ値を使うのが基本です。

ドラゴンボール風にたとえると、参加戦士が4人なら、記録枠も4つ、巡回回数も4回にそろえる必要があります。
4つしか枠がないのに10回巡回しようとすると、存在しない記録札を探すことになります。

図:入力された人数に合わせて配列とループをそろえる

この図が示していること

この図では、入力された人数 num を使って、配列の大きさとループ回数をそろえる流れを示しています。

num が 4 の場合、height = new int[num]; によって4個分の要素を持つ配列が作られます。

そして、for(int i = 0; i < num; i++) によって、i は 0、1、2、3 と変化します。

つまり、配列の添字として存在する範囲だけを、ループで順番に処理できます。

ここから分かることは、配列の大きさが実行時に決まる場合は、その大きさと同じ値をループ条件にも使うと、安全に処理しやすいということです。

配列とループを使うと柔軟なプログラムになる

配列とループを組み合わせると、プログラムがかなり柔軟になります。

利点内容
コードが短くなる同じ処理を何度も書かなくてよい
修正しやすい要素数が変わっても対応しやすい
ミスを減らせる手作業で添字を並べる量が減る
入力数に対応できる実行時に決まる個数に合わせられる
データを順番に処理できる表示、入力、集計などに使いやすい

特に、Sample2.java のように、入力された人数に合わせて配列を作る考え方は実用的です。

ドラゴンボール風にたとえると、訓練参加者が何人でも、その人数に合わせて記録棚を作れます。

4人なら4人分。
10人なら10人分。

そして、ループを使って人数分だけ入力し、人数分だけ表示できます。

人数が変わっても、考え方は同じです。
配列の大きさとループの回数をそろえることで、データを順番に処理できます。

配列とループで意識したいポイント

配列とループを組み合わせるときは、次の点を意識すると理解しやすくなります。

ポイント内容
配列の添字は0から始まる最初の要素は0番
ループ変数を添字に使えるi を使って data[i] のように扱える
最後の添字は要素数 - 1要素数5なら最後は4
ループ条件は範囲内にするi < 要素数 の形が基本
要素数が入力で決まる場合配列作成とループ条件に同じ値を使う

このあたりが整理できると、配列をただ保存するだけでなく、実際に処理するために使えるようになります。

特に大切なのは、data[i] のように、ループ変数を添字として使う考え方です。

data[i]

i が 0 なら data[0]。
i が 1 なら data[1]。
i が 2 なら data[2]。

このように、i の変化に合わせて、扱う要素も変わります。

ドラゴンボール風にたとえると、巡回番号 i が進むたびに、確認する記録札も次へ進むということです。

配列とループは集計や検索にもつながる

配列とループの組み合わせは、表示や入力だけで終わりません。

この考え方は、今後のJava学習で何度も使います。

この先できること配列とループの関係
合計を求める各要素を順番に足す
平均を求める合計を要素数で割る
最大値を探す要素を順番に比較する
最小値を探す要素を順番に比較する
条件に合う値を探すif文と組み合わせて判定する
一部のデータだけ表示する条件に合う要素だけ処理する

ドラゴンボール風にたとえると、記録棚を順番に見ていけば、全員の合計修行歩数、もっとも歩いた戦士、条件を満たした戦士などを調べられます。

配列はデータを並べる仕組みです。
ループはそのデータを順番に処理する仕組みです。

この2つがそろうと、たくさんのデータを扱うプログラムがぐっと書きやすくなります。

配列とループの基本をしっかり押さえよう

配列とループを組み合わせるときの基本は、次の流れです。

流れ内容
1配列を用意する
2要素に値を入れる
3for文で添字を順番に変える
4配列名[添字] で各要素を処理する
5配列の範囲を超えないように条件を書く

特に大切なのは、ループ変数を添字として使う考え方です。

data[i]

この形を理解できると、配列の要素を順番に扱えるようになります。

そして、配列の範囲を超えないためには、for文の条件を正しく書く必要があります。

for(int i = 0; i < 要素数; i++)

この形なら、i は 0 から 要素数 - 1 まで変化します。
配列の最初から最後までを、安全に処理できます。

配列とループの組み合わせは、Javaの実践的なプログラムを書くうえでとても大切です。

最初は、添字が0から始まることに少し戸惑うかもしれません。
でも、配列の並びとループの流れをセットで考えると、自然に理解しやすくなります。

ドラゴンボール風にたとえると、配列は「戦士たちの記録札を並べる棚」、ループは「その棚を順番に巡回する足運び」です。

この2つを組み合わせられるようになると、たくさんのデータをすっきり整理して処理できるようになります。