C#でプログラミングを行う際、複数のデータを格子状に管理できる「2次元配列」は非常に頻繁に利用されるデータ構造の一つです。

画像処理や行列計算、あるいはゲーム開発におけるマップデータの管理など、その用途は多岐にわたります。

しかし、いざプログラム内で配列のサイズに基づいてループ処理を行おうとした際、「行数や列数をどのように取得すればよいのか」で迷ってしまうケースが少なくありません。

C#の配列には、全要素数を返すプロパティや、特定の次元の長さを取得するためのメソッドが用意されていますが、多次元配列(矩形配列)とジャグ配列(配列の配列)では、そのアクセス方法が根本的に異なります。

本記事では、C#における2次元配列の要素数を正確に取得する方法について、GetLengthメソッドとLengthプロパティの違いを中心に、初心者の方から中級者の方まで役立つ知識を詳しく解説します。

C#における2次元配列の基本構造

C#で一般的に「2次元配列」と呼ぶものには、大きく分けて2つの種類が存在します。

一つはすべての行が同じ列数を持つ「多次元配列(矩形配列)」、もう一つは行ごとに列数が異なる可能性がある「ジャグ配列(配列の配列)」です。

これらは宣言の方法が異なるだけでなく、メモリ上での配置や要素数取得の挙動も異なります。

  • 多次元配列(矩形配列): int[,] matrix = new int[3, 4]; のように宣言します。
  • ジャグ配列(配列の配列): int[][] jagged = new int[3][]; のように宣言します。

本記事のメインテーマは、特に混乱を招きやすい多次元配列(矩形配列)における要素数取得ですが、比較のためにジャグ配列についても触れていきます。

GetLengthメソッドで特定の次元の要素数を取得する

多次元配列において、特定の次元(行方向や列方向)の要素数を取得するために最も推奨される方法がGetLengthメソッドです。

GetLength(0)とGetLength(1)の役割

GetLengthメソッドは、引数として「何番目の次元か」を指定する整数値(0から始まるインデックス)を受け取ります。

2次元配列の場合、以下のように対応しています。

  • GetLength(0): 第1次元の要素数、つまり「行数」を取得します。
  • GetLength(1): 第2次元の要素数、つまり「列数」を取得します。

以下のサンプルコードで、実際の挙動を確認してみましょう。

C#
using System;

class Program
{
    static void Main()
    {
        // 3行4列の2次元配列を宣言・初期化
        int[,] matrix = new int[3, 4];

        // 行数を取得 (第1次元)
        int rows = matrix.GetLength(0);

        // 列数を取得 (第2次元)
        int cols = matrix.GetLength(1);

        Console.WriteLine($"行数(Rows): {rows}");
        Console.WriteLine($"列数(Columns): {cols}");
    }
}
実行結果
行数(Rows): 3
列数(Columns): 4

なぜGetLengthを使うのか

多次元配列に対して後述するLengthプロパティを使用すると、すべての次元を掛け合わせた「全要素数」が返ってきます。

そのため、for文を使って行と列を個別にループ処理したい場合には、必ずGetLengthを使用してそれぞれの境界値を明示的に取得する必要があります。

LengthプロパティとGetLengthの違い

C#の配列には共通してLengthというプロパティが存在しますが、多次元配列におけるその挙動を正しく理解しておくことは、バグを防ぐ上で非常に重要です。

Lengthプロパティが返す値

多次元配列におけるLengthは、配列に含まれる全要素の合計数を返します。

例えば、3行4列の配列であれば、3 * 4 = 12 が返されます。

これを「行数」を取得するつもりで使用してしまうと、ループの回数が想定を超えてしまい、IndexOutOfRangeException(インデックス外参照)の原因となります。

GetLengthとLengthの比較表

取得したい項目使用するコード備考
全要素数array.Length3行4列なら 12 を返す
行数(第1次元)array.GetLength(0)3行4列なら 3 を返す
列数(第2次元)array.GetLength(1)3行4列なら 4 を返す

使い分けの基準

基本的には、多次元配列を扱う際は常にGetLengthを使用する習慣をつけておくと安全です。

Lengthを使用するのは、「メモリ確保の総量を確認したいとき」や「1次元配列としてフラットに扱いたいとき」などに限定されます。

実践:2次元配列をループで処理する

取得した行数と列数を使用して、2次元配列の全要素を走査する標準的なコード例を解説します。

もっとも一般的なのは、for文をネスト(入れ子)にする方法です。

C#
using System;

class Program
{
    static void Main()
    {
        // 2次元配列の初期化
        int[,] scores = {
            { 80, 90, 70 },
            { 55, 60, 45 },
            { 92, 88, 95 },
            { 40, 30, 50 }
        };

        // GetLengthで行数と列数を取得
        int rowCount = scores.GetLength(0);
        int colCount = scores.GetLength(1);

        Console.WriteLine($"データの形状: {rowCount}行 {colCount}列");
        Console.WriteLine("----------------------------");

        // ネストしたループで要素を表示
        for (int i = 0; i < rowCount; i++)
        {
            Console.Write($"行 {i}: ");
            for (int j = 0; j < colCount; j++)
            {
                // 特定の要素にアクセス
                Console.Write($"{scores[i, j]} ");
            }
            Console.WriteLine();
        }
    }
}
実行結果
データの形状: 4行 3列
----------------------------
行 0: 80 90 70 
行 1: 55 60 45 
行 2: 92 88 95 
行 3: 40 30 50

このコードでは、外側のループでGetLength(0)(行数)を利用し、内側のループでGetLength(1)(列数)を利用しています。

これにより、配列のサイズが変更されてもコードを修正することなく動的に対応可能です。

Rankプロパティによる次元数の取得

要素数そのものではありませんが、配列が「何次元なのか」を知る必要がある場合には、Rankプロパティを使用します。

次元の深さを確認する

例えば、メソッドの引数として配列を受け取り、それが2次元なのか3次元なのかを判定して処理を分けたい場合に有効です。

C#
int[,] array2D = new int[3, 3];
int[,,] array3D = new int[2, 2, 2];

Console.WriteLine(array2D.Rank); // 出力: 2
Console.WriteLine(array3D.Rank); // 出力: 3

Rankの値がnであれば、GetLength(0)からGetLength(n-1)までのインデックスが有効であることを意味します。

ジャグ配列(配列の配列)の場合の注意点

冒頭で触れた「ジャグ配列」は、多次元配列とは要素数の取得方法が大きく異なります。

ジャグ配列は「配列の中に配列が入っている」構造であるため、GetLengthメソッドではなくLengthプロパティを組み合わせて使用します。

ジャグ配列でのLengthの挙動

ジャグ配列 int[][] jagged において、jagged.Length は「外側の配列の要素数(行数)」を返します。

そして、各行の要素数(列数)を取得するには、jagged[i].Length のように、特定の行にアクセスしてからその長さを参照します。

C#
using System;

class Program
{
    static void Main()
    {
        // ジャグ配列の宣言(行ごとに列数が異なる)
        int[][] jaggedArray = new int[3][];
        jaggedArray[0] = new int[2];
        jaggedArray[1] = new int[5];
        jaggedArray[2] = new int[3];

        // 外側の配列の長さ(行数)
        Console.WriteLine($"行数: {jaggedArray.Length}");

        for (int i = 0; i < jaggedArray.Length; i++)
        {
            // 各行の配列の長さ(列数)
            Console.WriteLine($"行 {i} の列数: {jaggedArray[i].Length}");
        }
    }
}
実行結果
行数: 3
行 0 の列数: 2
行 1 の列数: 5
行 2 の列数: 3

このように、ジャグ配列ではGetLength(1)を呼び出すことはできません(実行時にエラーが発生するか、定義されていないためコンパイルエラーになります)。

自分が扱っている配列が「多次元配列([,])」なのか「ジャグ配列([][])」なのかを常に意識することが重要です。

LongLengthプロパティによる巨大な配列への対応

C#には、LengthプロパティのほかにLongLengthプロパティや、GetLongLengthメソッドも存在します。

通常のLengthint型(最大約21億)で値を返しますが、非常に巨大なデータを扱う場合、全要素数がintの範囲を超えてしまう可能性があります。

その場合、long型で値を返すこれらのプロパティ・メソッドを使用します。

C#
long totalSize = matrix.LongLength;
long rowCount = matrix.GetLongLength(0);

近年の64ビット環境での大規模データ処理や、高解像度の画像データをピクセル単位で扱うようなプログラムでは、念のためlong型での取得を検討するケースもあります。

よくある質問とトラブルシューティング

GetLength(1)を呼び出したらエラーになった

原因として最も多いのは、扱っている配列がジャグ配列(配列の配列)であるケースです。

ジャグ配列は多次元配列ではないため、GetLength(1)のように次元で直接扱うことはできません。

変数宣言がtype[,](2次元配列)になっているか確認してください。

2次元配列の全要素数をループなしで取得したい

単純に全要素の合計を知りたいだけであれば、matrix.Lengthプロパティを使用するのが最適です。

これにより、行数と列数を取得して掛け算する必要がなくなります。

動的にサイズが変わる2次元配列を扱いたい

C#の標準的な配列(Array)はインスタンス化の際にサイズが固定されます。

要素数が頻繁に変わるような行列を扱いたい場合は、List<List<int>>やカスタムの行列クラス、あるいは外部ライブラリ(例: Math.NET Numerics)の利用を検討してください。

これらでは要素数取得のプロパティ名がCountなど配列のLengthとは異なる点に注意してください。

まとめ

C#で2次元配列(多次元配列)の要素数を取得する際は、以下の3つのポイントを確実に押さえておきましょう。

  1. 行数・列数を個別に取得するには GetLength(n) を使用する。GetLength(0)は行数(第1次元)GetLength(1) は列数(第2次元)
  2. Lengthプロパティは全要素の合計(行 × 列)を返す。多次元配列のループ境界値として使用すると、範囲外アクセスの原因になるため注意が必要。
  3. ジャグ配列(配列の配列)の場合は Length を組み合わせて使用する。array.Length で行数を、array[i].Length で各行の列数を取得。

配列の要素数を正しく取得することは、堅牢なプログラムを書くための第一歩です。

特に多次元配列におけるGetLengthの使い分けをマスターすることで、多重ループなどの複雑なロジックを正確に制御できるようになります。

開発の現場では、配列の型や次元数に合わせて、最適なメソッドを選択するように心がけてください。