連載
» 2017年01月10日 05時00分 公開

Dev Basics/Keyword:ジャグ配列

ジャグ配列とは「配列の配列」を表す用語。ジャグ配列では配列の特定の次元の各要素が参照する配列の要素数が異なる場合がある。

[かわさきしんじ,Insider.NET編集部]
「Dev Basics/Keyword」のインデックス

連載目次

 ジャグ配列(Jagged Array)とは「配列の配列」(配列を要素とする配列)を表す用語。配列の特定の次元の各要素が参照する配列の要素数が異なっていても構わない(例えば、2次元の配列であれば、各行の列数が異なっていても構わない)。そのため配列の全体としての見た目が「ギザギザ」(jagged)に見える(ことがある)ことから、このように呼ばれている。

ジャグ配列と多次元配列

 ジャグ配列は「多次元配列」の一種と考えることもできる。多次元配列の特定の次元の各要素が格納する配列の要素数が同一である場合(例えば、2次元配列の各行の列数が同じ場合)、そのような配列を特に「矩形配列」(rectangular array)と呼ぶことがある。これに対して、「配列の配列」(ジャグ配列)ではある次元において各要素が参照する配列の要素数が異なる場合もあり、その場合、配列全体の見た目は矩形にはならない。

 C#など、多次元配列(矩形配列)とジャグ配列を明確に区別している言語も存在する。その一方で、ジャグ配列を利用して多次元配列を取り扱う言語もある。

ジャグ配列では配列全体の見た目がギザギザになる ジャグ配列では配列全体の見た目がギザギザになる

ジャグ配列の作成と利用

 C#でのジャグ配列の作成例を以下に示す。

class Program
{
  static void Main(string[] args)
  {
    int[][] jarray = new int[2][];
    jarray[0] = new int[] { 1, 2 };
    jarray[1] = new int[] { 3, 4, 5 };

    for (int i = 0; i < jarray.Length; i++)
    {
      for (int j = 0; j < jarray[i].Length; j++)
      {
        Console.WriteLine($"jarray[{i}][{j}]: {jarray[i][j]}");
      }
    }
    Console.ReadKey();
  }
}

ジャグ配列の作成と利用

 この例では、int配列を要素とする(1次元)配列jarray(jagged array)を作成して、その各要素をint配列で初期化した後に、その値をfor文の二重ループで利用している。変数jarrayが参照しているのはあくまでも1次元の配列であり、その要素がさらに1次元の配列を参照している。そして、「jarray[i][j]」としているように、ジャグ配列の要素にはインデクサーを重ねて、それがあたかも2次元配列であるかのようにアクセスできる。

 これに対して、上と同様なことをC#の多次元配列を使って行うコードは次のようになる。

class Program
{
  static void Main(string[] args)
  {
    int[,] rarray = new int[2, 3]  // rectangular array
    {
      { 1, 2, 0 },
      { 3, 4, 5 }
    };

    Console.WriteLine($"length(all): {rarray.Length}");

    foreach (var item in rarray)
    {
      Console.WriteLine(item);
    }

    for (var i = 0; i < rarray.GetLength(0); i++)
    {
      for (var j = 0; j < rarray.GetLength(1); j++)
      {
        Console.WriteLine($"rarray[{i}, {j}]: {rarray[i, j]}");
      }
    }
    Console.ReadKey();
  }
}

多次元配列の利用例

 まず、C#の多次元配列は矩形配列となるので、上のコードでは最初の行の3番目の要素には「0」を入れている(ジャグ配列にはなかった配列要素)。null許容型の配列を作成してnullをセットした方がよいかもしれない。大きく異なるのは配列要素へのアクセス方法で、ジャグ配列では「jarray[x][y]」だったのが「rarray[x, y]」のようになる点だ。

 また、配列の長さを求めている最初のConsole.WriteLineメソッド呼び出しでは「rarray.Length」としているが、これは配列全体の長さを取得するものだ。各次元の要素数を取得するには、forループで行っているようにGetLengthメソッドを使用する。最後に、foreach文を使うと、ループをネストさせることなく配列の各要素にアクセス可能だ(ただし、インデックス情報などは得られないので、細かな制御を行うのなら、その下のfor文のようにループをネストさせることになるだろう)。

 このようにC#ではジャグ配列と多次元配列ではその扱い方が明確に異なっているので、用途に合わせて適切なものを使うようにしたい。

 なお、実際にはジャグ配列の初期化はもっと簡単に次のように書いてもよい。ジャグ配列の初期化の方法についてはMSDNの「ジャグ配列 (C# プログラミング ガイド)」を参照されたい。

int[][] jarray = {
  new int[] { 1, 2 },
  new int[] { 3, 4, 5 }
};

初期化を簡略化

 また、LINQのSelectメソッドを使うとforeach文でもインデックスを取得/利用できる。

class Program
{
  static void Main(string[] args)
  {
    int[][] jarray = {
      new int[] { 1, 2 },
      new int[] { 3, 4, 5 }
    };

    foreach (var iarray in jarray.Select((v, i) => new { v, i }))
    {
      foreach (var item in iarray.v.Select((v, j) => new { v, j }))
      {
        Console.WriteLine($"jarray[{iarray.i}][{item.j}]: {item.v}");
      }
    }
    Console.ReadKey();
  }
}

Selectメソッドには要素のインデックスを含んだシーケンスを生成するオーバーロードがある

 参考までに同じことをJavaScriptで記述したものを以下に示しておこう。

var jarray = [
  [1, 2],
  [3, 4, 5]
];

jarray.forEach((iarray, i) => {
  iarray.forEach((item, j) => console.log(`jarray[${i}][${j}]: ${item}`))
})

JavaScriptにおけるジャグ配列の利用例

 Pythonでは次のようになる。

jarray = [
  [1, 2],
  [3, 4, 5]
]

for i, iarray in enumerate(jarray):
  for j, item in enumerate(iarray):
    print("jarray[", i, "][", j, "]: ", item, sep="")


Pythonでのジャグ配列の利用例

 なお、Python 3.6では文字列補間が可能になったことから最後のprint関数はもっと簡潔に「print(f"jarray[{i}][{j}]: {item}")」と記述可能だ。


 ジャグ配列とは「配列の配列」(配列を要素とする配列)を表す用語。ジャグ配列では配列の特定の次元の各要素が参照する配列の要素数が異なっていても構わない。C#のように多次元配列と明確に区別している言語もあれば、ジャグ配列を用いて多次元配列を実現している言語もある。

参考資料


「Dev Basics/Keyword」のインデックス

Dev Basics/Keyword

Copyright© 1999-2017 Digital Advantage Corp. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

この記事に関連するホワイトペーパー

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。