配列を返すメソッド

メソッドは配列を戻り値として返すこともできます。 ここでは、配列を返すメソッドについて学習しましょう。

配列のクローンを返す

第8章の配列の応用のところで学習したArraySample06は、配列本体をコピーするプログラムでした。

ArraySample06.java(再掲)
class ArraySample06 {
    public static void main(String[] args) {
        int[] a = {1, 2, 3, 4, 5};
        int[] b = {6, 7, 8, 9};

        System.out.print("aが指す配列本体は");
        for(int i = 0; i < a.length; i++)
            System.out.printf(" %2d", a[i]);
        System.out.println();
        System.out.print("bが指す配列本体は");
        for(int i = 0; i < b.length; i++)
            System.out.printf(" %2d", b[i]);
        System.out.println();

        b = new int[a.length];    //配列bの配列本体を生成し直す。
        for(int i = 0; i < a.length; i++)    //配列aの各要素を配列bへコピーする。
            b[i] = a[i];
        System.out.println("配列aを配列bにコピーしました。");
        b[0] = 10;
        System.out.println("b[0]に10を代入しました。");

        System.out.print("aが指す配列本体は");
        for(int i = 0; i < a.length; i++)
            System.out.printf(" %2d", a[i]);
        System.out.println();
        System.out.print("bが指す配列本体は");
        for(int i = 0; i < b.length; i++)
            System.out.printf(" %2d", b[i]);
        System.out.println();
    }
}

ArraySample06の実行結果は、図 9-8のようになりました。

図 9-8 : ArraySample06の実行結果

ArraySample06の配列本体をコピーする部分をメソッドとして独立させたものが、次のMethodSample10です。

MethodSample10.java
class MethodSample10 {
    /*---- 配列xのクローンを返す ----*/
    static int[] arrayClone(int[] x){
        int[] c = new int[x.length];
        for(int i = 0; i < c.length; i++)
            c[i] = x[i];
        return c;
    }

    /*---- 配列xの内容を表示する ----*/
    static void printArray(int[] x){
        for(int n : x)
            System.out.printf(" %2d", n);
        System.out.println();
    }

    public static void main(String[] args) {
        int[] a = {1, 2, 3, 4, 5};
        int[] b = {6, 7, 8, 9};

        System.out.print("aが指す配列本体は");    printArray(a);
        System.out.print("bが指す配列本体は");    printArray(b);

        b = arrayClone(a);
        System.out.println("配列aを配列bにコピーしました。");
        b[0] = 10;
        System.out.println("b[0]に10を代入しました。");

        System.out.print("aが指す配列本体は");    printArray(a);
        System.out.print("bが指す配列本体は");    printArray(b);
    }
}

実行結果はArraySample06と同じです。

arrayCloneメソッドは、受け取った配列のクローン(コピー)を作成し、戻り値として返します。 arrayCloneメソッドの戻り値の型は、 int[]と宣言されています。 つまり、int型の要素から成る配列への参照が返されるのです。

このメソッドは、内部で新しい配列本体を作成し、そこへ受け取った配列の要素を一つずつコピーしていくことで、クローンを完成させます。 そして、クローンへの参照を戻り値として返します。 mainメソッドに戻ると、戻り値が配列変数bに代入されます。 この結果、配列変数bと配列変数aは、内容は同じだが異なる配列本体をそれぞれ参照することになります。 この様子を示したのが図 9-9です。

本節で扱うメソッドは、厳密に言えば配列本体への参照を返すメソッドですが、話を簡単にするため、配列を返すメソッドという言い方をしています。

今回は配列の内容を表示する回数が多いので、表示専用のprintArrayメソッドを用意して、配列の表示をすべて任せています。

図 9-9 : 配列のクローンを返す

メソッドは配列本体への参照を返すことができる。

要素を削除した配列を返す

今度は単なるクローンではなく、何らかの新しい配列を作り、戻り値として返すことを考えてみましょう。 MethodSample11は、キーボードから読み込んだデータを配列に格納し、指定された要素を削除して、結果を表示するプログラムです。

MethodSample11.java
import java.io.*;

class MethodSample11 {
    /*---- 配列xからx[index]を削除した配列を返す ----*/
    static int[] arrayRemove(int[] x, int index){
        if(index < 0 || x.length <= index){
            return arrayClone(x);    // indexが範囲外の場合は、クローンを返す。
        }else{
            int[] y = new int[x.length - 1];
            int i = 0;
            for( ; i < index; i++)    // y[0] から y[index - 1]
                y[i] = x[i];
            for( ; i < y.length; i++)    // y[index] から y[y.length - 1]
                y[i] = x[i + 1];
            return y;
        }
    }

    /*---- 配列xのクローンを返す ----*/
    static int[] arrayClone(int[] x){
        int[] c = new int[x.length];
        for(int i = 0; i < c.length; i++)
            c[i] = x[i];
        return c;
    }

    public static void main(String[] args) throws IOException{
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));

        System.out.print("要素数 : ");    int num = Integer.parseInt(br.readLine());
        int[] a = new int[num];
        for(int i = 0; i < num; i++){
            System.out.print("a[" + i + "] : ");    a[i] = Integer.parseInt(br.readLine());
        }
        System.out.print("削除する要素のインデックス : ");
        int index = Integer.parseInt(br.readLine());
        int[] b = arrayRemove(a, index);
        for(int i = 0; i < b.length; i++)
            System.out.println("b[" + i + "] = " + b[i]);
    }
}
MethodSample11の実行結果 1
要素数 : 5
a[0] : 1
a[1] : 2
a[2] : 3
a[3] : 4
a[4] : 5
削除する要素のインデックス : 2
b[0] = 1
b[1] = 2
b[2] = 4
b[3] = 5
MethodSample11の実行結果 2
要素数 : 4
a[0] : 6
a[1] : 7
a[2] : 8
a[3] : 9
削除する要素のインデックス : 4
b[0] = 6
b[1] = 7
b[2] = 8
b[3] = 9

arrayRemoveメソッドは、配列xから要素x[index]を削除した配列を返します。 削除した要素以降は1つずつ左に詰めていきます。

    /*---- 配列xからx[index]を削除した配列を返す ----*/
    static int[] arrayRemove(int[] x, int index){
        if(index < 0 || x.length <= index){
            return arrayClone(x);    // indexが範囲外の場合は、クローンを返す。
        }else{
            int[] y = new int[x.length - 1];
            int i = 0;
            for( ; i < index; i++)    // y[0] から y[index - 1]
                y[i] = x[i];
            for( ; i < y.length; i++)    // y[index] から y[y.length - 1]
                y[i] = x[i + 1];
            return y;
        }
    }

まず、indexが0より小さい場合とx.length以上の場合は、x[index]が存在しないので、クローンを返すだけとなります。 この際MethodSample10で登場したarrayCloneメソッドを使っています。

それ以外の場合は、長さがx.length - 1の新しい配列yを生成して、配列xから配列yへx[index]以外の要素を一つずつコピーしていきます。 これを実際に行っているのが2つのfor文です。 どちらのfor文も初期化部が空になっていますね。 その代わり、1つ目のfor文の前にint i = 0;として、変数iを初期化しています。 そして、この変数iを2つのfor文で利用しているのです。 1つ目のfor文が終了した時点で、i = indexになっているので、2つ目のfor文はi = indexの状態から始まることになります。

実は、for文は初期化部、条件、更新部のいずれも空にすることができます。

実行結果 1で配列yを作成していく様子を示すのが、図 9-10です。

図 9-10 : 要素を削除した配列