第12回 2次元配列

今回は、2次元配列を見てみましょう。

Perlで配列は、@ なのですが、これ1次元配列なんですよね。
2次元配列自体は言語自体は持っていない。ということで、自分でつくらないといけないわけです。


まずは、失敗する例からみてみましょう。

use strict;
use Data::Dumper;

# 1次元配列
my @c = ('a', 'b', 'c');
my @d = ('e', 'f', 'g');
my @e = ('h', 'i', 'j', 'k', 'l');

# 上の1次元配列を各要素にもつ配列で、
# 2次元配列を実現しようとしてみる
my @f = (
         @c,
         @d,
         @e
        );

print Dumper \@f;

結果:

$VAR1 = [
          'a',
          'b',
          'c',
          'e',
          'f',
          'g',
          'h',
          'i',
          'j',
          'k',
          'l'
        ];

は!!! いったいなにがおきたのでしょうか!???

先にいっておきますと、この作戦は超おしぃいいいいいいい!
あとちょっとというところまできています。


では、なにが起きたかの説明なのですが、
第10回 今までの知識を総動員して、Data::Dumperを理解する - bingo_nakanishiの他言語出身者のためのPerl入門
の次の部分を思い出してください。


引用:

「配列」と「ハッシュ」はリファレンスにして渡してあげないと、まとまった値として受け取った関数の側がみてくれません。

じつは、これは、受け取る関数側の問題ではなく、

「関数呼び出し」のところをじっくり見てみると、

my @array = (1,2,'z');

hoge(@array);

↓

hoge(1,2,'z');  # このように展開される つまり引数を3つ与えたのと同じ

こういう解釈がされています。 ですから、この展開をさけるために「たったひとつ」であることを示すリファレンスで渡さなければいけません。

そうなんです。

my @f = (
         @c, # 展開される 
         @d, # 展開される
         @e  # 展開される
        );

↓

my @f = (
         'a', 'b', 'c',
         'e', 'f', 'g',
         'h', 'i', 'j', 'k', 'l'
        );

結局、自分の都合のいいところで、改行して書いた1次元配列と変わらねえええええええ!!!!
ということで、1次元配列になっちゃったのでした。


ちなみに、配列の構造はつぎのようになっていますよ。

そうなんです、配列の各要素には、スカラーな値(つまり$を頭にもつ変数ですね)しか持てないんです。
ですから、各要素に、@の配列を持たそうと思ったことが土台無理。


あー まいっちゃったなぁ
と、思う前に、


もう一度、

第7回 関数というかサブルーチン - bingo_nakanishiの他言語出身者のためのPerl入門

ビンゴ中西のほげほげ君のプログラムスタイルを抜本的に変える方法
です。


「配列」と「ハッシュ」はリファレンスにして渡してあげないと、まとまった値として受け取った関数の側がみてくれません。



そうだ!! 「配列」というまとまった値をスカラーで持ちたかったら リファレンスだ!!!!!


とうことで、
次のようにすればOK

se strict;
use Data::Dumper;

# 1次元配列
my @c = ('a', 'b', 'c');
my @d = ('e', 'f', 'g');
my @e = ('h', 'i', 'j', 'k', 'l');


# リファレンスで持たせるんだ!!!!
my @f = (
         \@c,
         \@d,
         \@e
        );

print Dumper \@f;

結果:

$VAR1 = [
          [
            'a',
            'b',
            'c'
          ],
          [
            'e',
            'f',
            'g'
          ],
          [
            'h',
            'i',
            'j',
            'k',
            'l'
          ]
        ];

おっしゃ!!!! いけたぜ!!!!!!!


ところで、はじめの、1次元配列を作っているところがみっともない。なさけない。なんで名前をつける必要があるのか。

use strict;
use Data::Dumper;

# リファレンスで持たせるんだ!!!!
# リファレンス取得するなら 無名配列で決まり!!
my @f = (
         ['a', 'b', 'c'],
         ['e', 'f', 'g'],
         ['h', 'i', 'j', 'k', 'l']
        );

print Dumper \@f;

ほら、無名配列 かっちょいいいい。
じっさい問題かっちょいいだけじゃなくて、可読性、メンテナンス性向上します。
その理由は、無名ハッシュの例になりますが、
ビンゴ中西のほげほげ君のプログラムスタイルを抜本的に変える方法
で述べている通り。



では、2次元配列のアクセスの例を、

se strict;
use Data::Dumper;

# リファレンスで持たせるんだ!!!!
# リファレンス取得するなら 無名配列で決まり!!
my @f = (
         ['a', 'b', 'c'],
         ['e', 'f', 'g'],
         ['h', 'i', 'j', 'k', 'l']
        );


print "$f[0]->[0]\n";
print "$f[0]->[1]\n";

結果:

a
b

インデックスの数字を変えて、 いろいろ出力させてみてください。


あとは、

use strict;
use Data::Dumper;

# リファレンスで持たせるんだ!!!!
# リファレンス取得するなら 無名配列で決まり!!
my @f = (
         ['a', 'b', 'c'],
         ['e', 'f', 'g'],
         ['h', 'i', 'j', 'k', 'l']
        );


for( @{$f[2]} ){
  print "$_", "\n";
}

結果:

h
i
j
k
l

こんな感じです。 


しかし、Data::Dumper はすごいですね。

se strict;
use Data::Dumper;

# リファレンスで持たせるんだ!!!!
# リファレンス取得するなら 無名配列で決まり!!
my @f = (
         ['a', 'b', 'c'],
         ['e', 'f', 'g'],
         ['h', 'i', 'j', 'k', 'l']
        );

print Dumper \@f;

結果:

$VAR1 = [
          [
            'a',
            'b',
            'c'
          ],
          [
            'e',
            'f',
            'g'
          ],
          [
            'h',
            'i',
            'j',
            'k',
            'l'
          ]
        ];

ちなみにですね。
他言語だと(C言語とか)2次元配列の各要素にアクセスするときは、

a[0][0]

こんな感じで、 と [ ]が繋がっとるわけです。
実は、これPerlでもいけちゃうんですな。

print "$f[0]->[0]\n";

↓

print "$f[0][0]\n";  # こうも書ける



カッコとカッコの間 の「間」というところが重要です。
それ以外のデリファレンスの矢印「->」は省略できません。

しかし、僕はあんまり省略して書きません。
デリファレンスしている感じが薄れるからです。

これは、完全に他言語出身者への配慮です。
Perl使いならなんとなく 「->」を省略したくないのは僕だけでしょうか?



とまあ、こんな感じで2次元配列が作れます。
3次元でも何次元でも、配列の要素にどんどんリファレンスを持たせることで可能となります。


ということで2次元配列でしたー。
それでは また〜