まくまくPerlノート
配列の配列(二次元配列)を作成する
2008-02-28

多次元配列を作成する

配列の配列 (array of array) (2 次元配列)を作りたい場合は、単純に 2 つのインデックスを括弧で繋げて指定します。

例: 要素を一つずつ代入して作る

my @aoa;
for my $x (0..5) {
    for my $y (0..9) {
        $aoa[$x][$y] = $x * $y;
    }
}
print $aoa[2][8];    # 16

配列コンストラクタ () を使って 2 次元以上の配列を作成する場合は、配列の要素として配列リファレンスを含むようにしなければいけません。

例 (1) 無名配列コンストラクタを利用:

my @aoa = (
    ['aaa', 'bbb', 'ccc'],
    ['ddd', 'eee', 'fff'],
    ['ggg', 'hhh', 'iii'],
);
print $aoa[0][2];  # 'ccc'

例 (2) 既存の配列を参照するようにする:

my @array1 = (0, 1, 2);
my @array2 = (3, 4, 5);
my @aoa = (\@array1, \@array2);
print $aoa[0][2];    # 2

# ちなみに、@array1、@array2 の内容をコピーして要素を作りたい場合は
# 次のように無名配列コンストラクタ [] を使って配列の要素をコピーして
# 新たにメモリを割り当てます。こうすれば、@aoa をいじっても、
# @array1 と @array2 の内容は変わりません。
my @aoa = ([@array1], [@array2]);

配列の要素としてそのまま配列を入れようとすると、連結された 1 次元の配列になってしまいます。

間違った例 (1):

my @array = ((0, 1, 2), (3, 4, 5));  # (0, 1, 2, 3, 4, 5) になってしまう

間違った例 (2):

my @array1 = (0, 1, 2);
my @array2 = (3, 4, 5);
my @array3 = (@array1, @array2);  # (0, 1, 2, 3, 4, 5) になってしまう

多次元配列の要素を参照する

2階層目以下の要素を参照する場合は、実際には配列リファレンスにアクセスするわけですが、通常はデリファレンスの記号 (->) を省略できます。

my @aoa = ([0, 1, 2], [3, 4, 5]);
print $aoa[0][2];    # OK
print $aoa[0]->[2];  # 冗長

ただし、リファレンス変数からアクセスする場合は、必ず最初にデリファレンスの矢印が必要になります(詳しくは、perldoc perldsc を参照)。

# $aoa はリファレンスなので、矢印 (->) を使って
# デリファレンスを明示する必要がある
my $aoa = [['a', 'b', 'c'], ['d', 'e', 'f']];
print $aoa->[0][2];    # 'c'
print $aoa->[0]->[2];  # これも同様だが冗長

# これはダメ! @aoa という配列にアクセスしようとしてしまう!
print $aoa[0][2];  # NG

下記は、二次元配列をループで処理する例です。

@arr = (
    ['a0'..'a9'],
    ['b0'..'b9'],
    ['c0'..'c9'],
    ['d0'..'d9'],
);

# 多次元配列の要素を表示する例
for ($i = 0; $i < @arr; $i++) {
    for ($j = 0; $j < @{$arr[$i]}; $j++) {
        print $arr[$i]->[$j], ",";
    }
    print "\n";
}
2008-02-28