配列変数

大量のデータを扱う場合の処理

前回までの内容で、C#言語のアルゴリズムの三大要素が全て出そろいました。しかし、これだけでは十分なプログラムができるわけではありません。冒頭にも書いた通りプログラムを記述するためにはアルゴリズムとデータ構造という二大要素があることは説明したと思います。

ここからは、いよいよデータ構造について説明していきます。実用的なプログラムを作るときに必要なデータ構造はたくさんありますが、ここでは特にここでは大量のデータを扱う場合に必要な配列(はいれつ)について説明します。

C#言語では、変数を用いて大量のデータを扱う場合、配列変数(はいれつへんすう)を用います。ここでは、配列変数の使い方を学ぶことにしましょう。

サンプルプログラム

配列変数について詳しく説明する前に、まずは以下のプログラムを入力・実行してみてください。

プロジェクト:Sample501/ファイル名Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Sample501
{
    class Program
    {
        static void Main(string[] args)
        {
            double one,two,three;
            double sum,avg; //  合計値、平均値を入れる変数
            one = 1.2;
            two = 3.7;
            three = 4.1;    //  変数の代入
            Console.WriteLine(one + " " + two + " " + three);
            sum = one + two + three;    //  合計値の計算
            avg = sum / 3.0;            //  平均値の計算
            Console.WriteLine("合計値:" + sum);
            Console.WriteLine("平均値:" + avg);
        }
    }
}
実行結果
1.2 3.7 4.1
合計値:9
平均値:3

このケースは、数値が3つだからよいですが、もしももっと増えたらどうなるでしょう?four,five,と、次々に定義する変数の数を増やしていかなくてはなりません。 しかし、このプログラムを、以下のように変更すると、大変楽になります。

プロジェクト:Sample502/ファイル名Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Sample502
{
    class Program
    {
        static void Main(string[] args)
        {
             double[] d = new double[3];
             d[0] = 1.2;
             d[1] = 3.7;
             d[2] = 4.1;    //  変数の代入
             double sum,avg; //  合計値、平均値を入れる変数
             sum = 0.0;
             for(int i = 0; i < d.Length; i++){
                 Console.Write(d[i] + " ");
                 sum += d[i];
            }
            Console.WriteLine();
            avg = sum / d.Length;
            Console.WriteLine("合計値:" + sum);
            Console.WriteLine("平均値:" + avg);
        }
    }
}

実行結果は、Sample501と一緒です。若干プログラムは長くなってしまいましたが、もしも変数が5個、10個、100個・・・と増えたときを考えてみてください。こちらのほうが、プログラムを変更する手間が少なそうです。

配列の大きさ

13行目に出てくる、d.Lengthは、配列変数の成分の数を表します。この場合、dの成分は3つあるので、d.Lengthは3となります。

配列の長さ
(配列変数名).Length

これを用いることにより、配列変数の長さを取得することができます。

配列変数

では、一体、このプログラムはどのような仕組みになっているのでしょうか?6行目に出てくる、double d[] = new double[3];という記述が、配列変数(はいれつへんすう)の宣言です。配列変数とは、同一の名前で多数のデータを格納できる変数のことで、単に配列(はいれつ)とも呼ばれます。配列の諸式は以下のようになります。

配列の宣言
(変数の型名)[] (変数名)= new (変数の型名)[配列の数];

したがって、この例で13行目は、double[] d = new double[3];と書くこともできます。

配列変数にも、変数名が存在します。この場合、dが変数名になります。[]の中に記述されているのが、配列の大きさで、この場合、サイズは3になります。

添字

この処理により、d[0]、d[1]、d[2]という3つのdouble型の変数が使用可能になります(図5-1)。14行目から16行目の間で、これらの変数に値を代入しています。なお、ここで[]の中に書いてある数字を、添字(そえじ)と言います。例えば、「d[1] = 3.7;」という処理は、この配列の2番目の変数に、3.7という値を代入することを意味します(図5-2)。この数値は必ず0から始まりますので、配列の大きさが3の場合は、2までになります。

図5-1.配列の宣言図5-2.配列変数への値の代入
Javaの配列の宣言Javaの配列変数への代入

添字が、配列の範囲を超えていてもエラーにはなりませんが、実行時に異常終了したりすることがありますので、気をつけましょう。

配列変数を使うメリットは、実はこの添字が使えることにあります。19行目から22行目のforループの中で、添字に整数型変数iを用いています。これにより、プログラムを変更して、配列の大きさを変化させても、for文に条件式の値を変化させるだけで対応できます。

配列の初期化

ところで、配列変数の宣言と初期化ですが、もう少し、楽にならないものなのでしょうか?実は、以下のようにすると、配列変数の宣言と初期化を一度に行うことができます。

プロジェクト:Sample503/ファイル名Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Sample503
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] n = { 5,4,3,2,1 };
            string[] s = { "ABC","DEF","GHI" };
            int i;
            //  整数型配列変数nの成分表示
            for(i = 0; i < n.Length; i++){
                Console.Write(n[i]+" ");
            }
            Console.WriteLine();
            //  文字列型配列変数nの成分表示
            for(i = 0; i < s.Length; i++){
                Console.Write(s[i]+" ");
            }
            Console.WriteLine();
        }
    }
}
実行結果
5 4 3 2 1
ABC DEF GHI

実行結果を見るとわかるように、13~14行目で行っている処理は、配列のを生成し、同時に値を代入しています。例えば、nについては、以下のような処理を行っています。

配列の宣言と初期化
int n[] = { 5,4,3,2,1 };
    ↓ この処理は、以下の処理に相当
int n[] = new int[5];
n[0] = 5;
n[1] = 4;
n[2] = 3;
n[3] = 2;
n[4] = 1;

文字列変数sについても同様で、3個の成分を作り、s[0]からs[2]に値を「ABC」「DEF」「GHI」にしています。

foreachループ

サンプルプログラム

4日目で、forやwhileを始めとする繰り返し処理について説明しました。それらと同様に、配列の内容の出力に使える繰り返し処理があります。それが、foreachです。これを使えば、forループよりもシンプルに配列の成分をすべて取得することができます。

プロジェクト:Sample504/ファイル名Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Sample504
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] n = { 1, 2, 3, 4 };
            foreach(int i in n){
                Console.Write("{0} ",i);
            }
            Console.WriteLine();
        }
    }
}

実行結果
1 2 3 4

foreachの書式

foreachの書式は、以下のようになります。

foreachの書式
foreach(変数 in 配列変数)

これにより、配列変数の値が、一つ一つ変数に入っていきます。そして、すべての値が変数に入ると、ループが終了します。配列の内容をすべて出力する場合は、forループを使うよりもこちらの方が便利です。

多次元配列

サンプルプログラム

次に、配列変数の応用である、多次元配列(たじげんはいれつ)について説明しましょう。多次元配列とは、複数の添字をつけることができる配列変数です。そのなかで、最も基本となる二次元配列の例をここでは紹介します。以下のプログラムを実行してみてください。

プロジェクト:Sample505/ファイル名Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Sample505
{
    class Program
    {
        static void Main(string[] args)
        {
            int[,] a = new int[3,4];
            int m,n;
            //  二次元配列に値を代入
            for(m = 0; m < 3; m++){
                for(n = 0; n < 4; n++){
                    a[m,n] = m+n;
                }
            }
            //  二次元配列に値を出力
            for (m = 0; m < 3; m++)
            {
                for (n = 0; n < 4; n++)
                {
                    Console.Write("a[{0},{1}]={2} ", m, n, a[m, n]);
                }
                Console.WriteLine();
            }
        }
    }
}
実行結果
a[0,0]=0 a[0,1]=1 a[0,2]=2 a[0,3]=3
a[1,0]=1 a[1,1]=2 a[1,2]=3 a[1,3]=4
a[2,0]=2 a[2,1]=3 a[2,2]=4 a[2,3]=5

二次元配列

二次元配列aには、2つの添え字をつけることができます。これにより、二次元の配列を作ることが可能です。(図5-3)

図5-3.二次元配列のイメージ
二次元配列のイメージ

配列の最初の引数と、次の引数の間は、,(コンマ)で区切ります。同様にして、三次元、四次元といったた次元の配列を作ることも可能です。

多次元配列の宣言と成分へのアクセスの方法
二次元配列int[,] a = new int[3,4];a[1,2] = 2;
三次元配列int[,,] a = new int[3,4,5]a[1,2,3] = 2;
四次元配列int[,,,] a = new int[3,4,5,6]a[1,2,3,4] = 2;

多次元配列の理由範囲は非常に高く、さまざまな表や、座標などのデータを表すものとして使用されます。わかりやすい例でいくと、表計算のような処理は、2次元配列を用いれば、非常に簡単に実現できます。

ジャグ配列

サンプルプログラム

Sample505では、長方形の形になる二次元配列でしたが、この配列の構造は、不揃いにすることができます。これを、ジャグ配列と言います。以下のサンプルを実行してみてください。

プロジェクト:Sample506/ファイル名Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Sample506
{
    class Program
    {
        static void Main(string[] args)
        {
            int[][] a = new int[][]{new int[]{0,1},new int[]{2},new int[]{3,4,5,6}};
            //  成分の表示
            for(int m = 0; m < a.Length; m++){
                for(int n = 0; n < a[m].Length; n++){
                    Console.Write(a[m][n]+" ");
                }
                Console.WriteLine();
            }
        }
    }
}

実行結果
0 1
2
3 4 5 6

このように、縦、横の成分がばらばらになるようなケースもあります。図にすると、以下のようなイメージになります。(図5-4.)

図5-4.不揃いな配列のイメージ
二次元配列のイメージ

練習問題 : 問題5.