[C#]多次元配列・配列の配列を初期化する、データを取得する

いつも必要になる頃には(書き方を)忘れているので、備忘録。
それぞれの使い分け、利点・欠点についても考えてみます。

多次元配列 (Rectangular Array)

初期化

縦が「行」、横が「列」
int[,] blank = new int[3,3];

int[,] data = new int[,]
{
    { 166, 59, 37 },
    { 176, 94,232 },
    { 73, 154, 98 },
};

初期化の書式はこちらの方が直感的です。一次元ごとに中括弧で区切るだけ。
配列の大きさを記述する必要もありません。

ループして全データ取得

string str = "";

for (int i = 0; i < data2.GetLength(0); i++)
{
    for (int j = 0; j < data2.GetLength(1); j++)
    {
        str += data2[i,j] + ",";
    }
}

Debug.Log(str);

Length ではなく GetLength を使う必要がある点は注意ですが、記述はシンプル。
Length には全データ数(例だと 3 x 3 = 9)が入っています。

解説

C# の多次元配列と言えばこちらがスタンダードでしょうか。
配列のサイズを予め決めておく必要があるので、個人的には不便だと思うことが多いです。

メモリ効率はこちらの方が上ですが、使い方によっては無駄になるケースもあるかもしれません。

1行のデータ長が決まっていない場合、最長に合わせる必要があるのでメモリロスとなることもある。

動作速度については、こちらの方が基本有利でしょう。

1次元配列を見せかけだけ多次元にしているイメージ?

data[0,2] のようにアクセスします。1番目の数字が行、2番目の数字が列です。

配列の配列 (Jagged Array)

初期化

縦が「行」、横が「列」
int[][] blank = new int[3][];

int[][] data = new int[][]
{
    new int[] { 166, 59, 37 },
    new int[] { 176, 94,232 },
    new int[] { 73, 154, 98 },
};

int[][] data2 = new int[][]
{
    new int[] { 166, 59, 37 },
    new int[] { 176 },
    new int[] { 73, 154 },
};

2次元目で大きさを指定しなかった分、こちらの初期化は毎行 new int[] をつける必要があります。
いささか面倒。

ただ、サイズを固定にする必要がないということで、data2のような初期化もできます。

配列はリストに置き換えられる

配列の配列からは少しそれますが、こういう事も可能だったりします。
これなら横方向は動的に、いくらでもデータを足し引きできますね。

List<int>[] data2 = new List<int>[]
{
    new List<int> { 166, 59, 37 },
    new List<int> { 176 },
    new List<int> { 73, 154 },
};

さらに一歩進めて、縦横両方リスト化します。
こうすれば全て、動的なデータの足し引きが可能。

リストは1次元配列を動的に増減できる上位装置なので、「配列の配列」は「リストのリスト」に置き換え可能なのです。

List<List<int>> data = new List<List<int>>
{
    new List<int> { 166, 59, 37 },
    new List<int> { 176 },
    new List<int> { 73, 154 },
};

なにかを作り込めば作りこむほど、データサイズを固定にすることはリスクになることが多いです。
頭の中で固定領域を作らない、こういったデータ構造を理解することは、地味ですが大事なことだと思います。

データサイズを動的に変更する必要がなければ、多次元配列のようなデータの持ち方が効率的です。
必要に応じて使い分けます。

ループして全データ取得

string str = "";

for (int i = 0; i < data.Length; i++)
{
    for (int j = 0; j < data[i].Length; j++)
    {
        str += data[i][j] + ",";
    }
}

Debug.Log(str);

これも、慣れてないと少し混乱しそうな記述ですね。
配列ではなくリストにしたい場合、Length Count に変更します。

慣れてくると、こっちの方がシンプルに見えてくる不思議

解説

多次元配列を C から使っている人はこちらの方がなじみ深いかもしれません。

ポイント(かつ、混乱しやすい点)は、2次元目の配列サイズを固定にする必要がない(できない)点です。
new int[3][] と、2次元目に数字(配列の大きさ)を入れられない事に最初は戸惑うと思います。

次に、毎回 data[0][2] のようなデータアクセスをした場合、(IL 次第ですが)速度ロスが大きくなるかもしれません。
var d = data[0] としておいて d[2] とアクセスする事で効率的になりますし、コードの見かけもスッキリします。

どっちを使うべき?

初心者の方は特にそう思うんじゃないでしょうか?
「なんで2つもあるの?」と迷っちゃいますよね。

正直どちらにも利点、欠点があるので決まった答えはありませんが、配列の配列で組んでおいた方が後々の拡張性で有利なケースが多いかな……と思います。

反面、直感的で初心者に優しいのは多次元配列だと思います。エクセル的ですし。
ゲームの2次元マップのように必ず大きさが決まっている場合は多次元配列で構わないんじゃないでしょうか。

慣れてきたら、先ほどの利点や欠点を思い出しつつ、使い分けていきましょう。

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA