配列とハッシュの基本的な作成・アクセス方法を確認する。
use strict; use warnings; use Data::Dumper; my @ary1 = (1, 2, 3, (4, 5, 6), (7, (8, 9), ), ); print @ary1, "\n"; print Dumper(@ary1), "\n"; print $ary1[0], "\n"; print $ary1[@ary1-1], "\n";
123456789 # ← print @ary1 $VAR1 = 1; $VAR2 = 2; $VAR3 = 3; $VAR4 = 4; $VAR5 = 5; $VAR6 = 6; $VAR7 = 7; $VAR8 = 8; $VAR9 = 9; #(ここまでがDumper(@ary1)の出力) 1 # ← print $ary1[0] 9 # ← print $ary1[@ary1-1]
配列作成時の"(...)"は、配列の実体(*1)を作成するコンストラクタ。
従って、変数の"ary1"は、常にリストとして"@"でアクセスする必要がある。
print Dumper($ary1), "\n";
は、
Global symbol "$ary1" requires explicit package name at hoge.pl line 7. Execution of hoge.pl aborted due to compilation errors.
となる。すなわちスカラーとしての"ary1"をシンボルテーブルから探そうとしてしまう。
次の記法にも注意。
print $ary1[@ary1-1], "\n";
要するに配列の最大要素数-1により、配列の末尾にアクセスしている。ここで@ary1 を -1 することで、
ということで、配列の末尾要素にアクセスできている。
my $ary2 = [ 1, 2, 3, (4, 5, 6), [7, 8, 9] ]; print $ary2, "\n"; print Dumper($ary2), "\n"; print $ary2->[0], "\n"; print $ary2->[6], "\n"; print $ary2->[6][0], "\n"; my $ary_buf = $ary2->[6]; print $ary_buf->[0], "\n"; print $ary_buf->[@$ary_buf - 1], "\n";
ARRAY(0x18c35ac) # ← print $ary2 $VAR1 = [ 1, 2, 3, 4, 5, 6, [ 7, 8, 9 ] ]; 1 # ← print $ary2->[0] ARRAY(0x274e6c) # ← print $ary2->[6] 7 # ← print $ary2->[6][0] 7 # ← print $ary_buf->[0] 9 # ← print $ary_buf->[@$ary_buf - 1]
"[", "]"は''名無し配列コンストラクタ''(Effective Perl)であり、その返すものはリファレンスである。従って、リファレンス全般で要素アクセスに使われる"->"を用いて各インデックスの値にアクセスできる。
前掲のコードピースでは名無し配列を多段に組んでいる。この場合、入れ子になった配列のリファレンスを取り出し、$ary_bufとしてアクセスできている。
$ary2->[6][0]
も、
$ary_buf->[0]
も、両方同じ"7"を取得できている。
my @ary3 = (1, 2, 3); print join(" ", @ary3), "\n"; # ... (a) for(my $i = 0; $i < @ary3; $i++) { $ary3[$i]++; } print join(" ", @ary3), "\n"; # ... (b) foreach my $e (@ary3) { $e++; } print join(" ", @ary3), "\n"; # ... (c) foreach (@ary3) { $_++; } print join(" ", @ary3), "\n"; # ... (d) for my $i (@ary3) { $i++; } print join(" ", @ary3), "\n"; # ... (e) for (@ary3) { $_++; } print join(" ", @ary3), "\n"; # ... (f)
1 2 3 # (a) 2 3 4 # (b) 3 4 5 # (c) 4 5 6 # (d) 5 6 7 # (e) 6 7 8 # (f)
(a)は基本中の基本であるが、よりエレガントに見える書き方は (d) や (f) であろう。いずれにせよ、どの書き方も正しく配列の要素を+1できている。
なお、前掲のコードピースは配列の実体を対象にしてのコードだった。下記に、同じ出力結果になる、名無し配列リファレンスを使用した場合のコードを示す。
my $ary3b = [1, 2, 3]; print join(" ", @$ary3b), "\n"; for(my $i = 0; $i < @$ary3b; $i++) { $ary3b->[$i]++; } print join(" ", @$ary3b), "\n"; foreach my $e (@$ary3b) { $e++; } print join(" ", @$ary3b), "\n"; foreach (@$ary3b) { $_++; } print join(" ", @$ary3b), "\n"; for my $i (@$ary3b) { $i++; } print join(" ", @$ary3b), "\n"; for (@$ary3b) { $_++; } print join(" ", @$ary3b), "\n";
print するだけのミニマムテストでは分かりづらいが、
print $ary[0]
と
print @ary[0]
は異なる。
前者は"$"が付いている為スカラーコンテキストで評価され、配列の要素としてアクセスされる。後者は"@"が付いている為、配列、すなわち''スライス''としてアクセスされる。
my @ary4 = ("abc", "def", "ghi", "jkl", "mno"); print $ary4[0], "\n"; print @ary4[0], "\n"; # ← (a) print $ary4[1, 2], "\n"; # ← (b) print join(" ", @ary4[1, 2]), "\n"; print join(" ", @ary4[1 ... 4]), "\n"; print join(" ", @ary4[1 ... 5]), "\n"; # ← (c)
Scalar value @ary4[0] better written as $ary4[0] at ... (a) Multidimensional syntax $ary4[1, 2] not supported at ... (b) abc # ← print $ary4[0] abc # ← print @ary4[0] ... (a) ghi # ← print $ary4[1, 2] ... (b) def ghi # ← print join(" ", @ary4[1, 2]) def ghi jkl mno # ← print join(" ", @ary4[1 ... 4]) Use of uninitialized value in join or string at ... (c) def ghi jkl mno
(a), (b) のようにスカラーが予想される値を"@"としてアクセス(a)したり、スライスが予想される値を"$"としてアクセス(b)すると、警告が発せられる。
またスライスでも、要素INDEXを越えてアクセスしようとすると(c)のように警告が発せられる。
書いている本人自身も実は何回も間違えているように、Perl初学者にとってはとにかく間違いやすい。 Perlにおいてはコンテキストが重要であり、変数がどのコンテキストで評価されるのかは、その冒頭に付く文字($, @, %, *)で判断される (それに加えて、前後のコードも関係する)。これについて、人間側で感情的な割り切りを行えれば、大分Perlの学習と理解も進むのかも知れない。
my @ary5 = ("abc", "def", "ghi", "jkl", "mno"); #--------------------- (a) : 末尾要素を削除 my $buf = pop @ary5; print join(" ", @ary5), "\n"; print $buf, "\n"; #--------------------- (b) : 末尾要素に追加 $buf = push(@ary5, 7); print join(" ", @ary5), "\n"; print $buf, "\n"; #--------------------- (c) : 先頭要素を削除 $buf = shift @ary5; print join(" ", @ary5), "\n"; print $buf, "\n"; #--------------------- (d) : 先頭要素に追加 $buf = unshift(@ary5, "xyz"); print join(" ", @ary5), "\n"; print $buf, "\n"; #--------------------- (e) : スカラーコンテキストで評価 print scalar(@ary5), "\n";
#--------------------- (a) : 末尾要素を削除 abc def ghi jkl mno # 削除された要素の値 #--------------------- (b) : 末尾要素に追加 abc def ghi jkl 7 5 # 追加後の配列の要素数 #--------------------- (c) : 先頭要素を削除 def ghi jkl 7 abc # 削除された要素の値 #--------------------- (d) : 先頭要素に追加 xyz def ghi jkl 7 5 # 追加後の配列の要素数 #--------------------- (e) : スカラーコンテキストで評価 5
undef代入の幾つかのパターンと、空のリストで有ることをどうやって判別を示す。
#--------------------- (a) my @ary6 = (); if(@ary6) { print Dumper @ary6, "\n"; } else { print "ary6 is not defined.(a)\n"; } #--------------------- (b) @ary6 = undef; if(@ary6) { print Dumper @ary6, "\n"; } else { print "ary6 is not defined.(b)\n"; } #--------------------- (c) @ary6 = 1 .. 5; @ary6[2, 4] = undef; print Dumper @ary6, "\n"; #--------------------- (d) undef @ary6; if(@ary6) { print Dumper @ary6, "\n"; } else { print "ary6 is not defined.(d)\n"; }
#--------------------- (a) ary6 is not defined.(a) #--------------------- (b) $VAR1 = undef; $VAR2 = ' '; #--------------------- (c) $VAR1 = 1; $VAR2 = 2; $VAR3 = undef; $VAR4 = 4; $VAR5 = undef; $VAR6 = ' '; #--------------------- (d) ary6 is not defined.(d)
注意すべきは、 defined は Perl5.004以降、スカラー変数を対象とするようになり、配列やハッシュは非推奨になっている 点である。
このため、下記のコードはwarningを生成する。
if(defined(@ary6)) { ... → defined(@array) is deprecated at ... (Maybe you should just omit the defined()?)
では、厳密な意味で "@ary6" がundefなのか、空リストであるのか、をどうやって見分けるのか?については残念ながら現段階では調べ切れていない。%::などを用いて直接シンボルテーブルにアクセス・・・しても、lexical変数であればそれも無意味である。
とりあえず、
my @ary = (); # or undef @ary;
は偽になるが、
my @ary = undef;
は偽にならないという点に十分注意する。
ハッシュについてはその基本操作の殆どが、冒頭でリンクとして挙げたPerl講座で網羅されている。ここでは実体のコンストラクタである"(", ")"と、リファレンスコンストラクタ"{", "}"の差異をメインに、ざっと流すに留める。(*3)
my %h1 = ( abc => 123, "def" => 456, 'ghi' => 789 ); #--------------------- (a) print Dumper(%h1), "\n"; #--------------------- (b) print $h1{'abc'}, "\n"; #--------------------- (c) while(my ($key, $val) = each(%h1)) { print "[$key] = $val\n"; }
#--------------------- (a) $VAR1 = 'def'; $VAR2 = 456; $VAR3 = 'abc'; $VAR4 = 123; $VAR5 = 'ghi'; $VAR6 = 789; #--------------------- (b) 123 #--------------------- (c) [def] = 456 [abc] = 123 [ghi] = 789
for my $key (sort(keys(%h1))) { print "[$key] = ", $h1{$key}, "\n"; } → [abc] = 123 [def] = 456 [ghi] = 789
"(", ")"を用いるとハッシュの実体を作成できた。続いて、 名無しハッシュ のコンストラクタである"{", "}"の使用例を示す。
my $h2 = { abc => 123, "def" => (4, 5, 6), "ghi" => [7, 8, 9 ] }; #--------------------- (a) print Dumper($h2), "\n"; #--------------------- (b) print $h2->{'abc'}, "\n"; print $h2->{'def'}, "\n"; print $h2->{'ghi'}, "\n"; print $h2->{'ghi'}->[0], "\n"; print $h2->{'ghi'}->[1], "\n"; print $h2->{'5'}, "\n"; #--------------------- (c) while(my ($key, $val) = each(%$h2)) { print "[$key] = $val\n"; }
#--------------------- (a) $VAR1 = { 'def' => 4, 'abc' => 123, 'ghi' => [ 7, 8, 9 ], '5' => 6 # ← !!注意!! }; #--------------------- (b) 123 # $h2->{'abc'} 4 # $h2->{'def'} ARRAY(0x275028) # $h2->{'ghi'} 7 # $h2->{'ghi'}->[0] 8 # $h2->{'ghi'}->[1] 6 # $h2->{'5'} #--------------------- (c) [def] = 4 [abc] = 123 [ghi] = ARRAY(0x275028) [5] = 6 # ← !!注意!!
実際のところ、"=>"を使用せずともハッシュは作れるようである。要は変数が"%"としてハッシュコンテキストで実体が代入されるか、"{", "}" で囲まれたリストとしてハッシュのリファレンスで代入されるか、どちらでもハッシュとして扱えるようである。
my %h3 = ( "abc", 123, "def", 4, 5, 6, "ghi", [7, 8, 9] ); my $h4 = { "abc", 123, "def", 4, 5, 6, "ghi", [7, 8, 9] }; #--------------------- (a) print Dumper(%h3), "\n"; print Dumper(%$h4), "\n"; #--------------------- (b) print Dumper(\%h3), "\n"; print Dumper($h4), "\n";
#--------------------- (a) # %h3 $VAR1 = 'def'; $VAR2 = 4; $VAR3 = 'abc'; $VAR4 = 123; $VAR5 = 'ghi'; $VAR6 = [ 7, 8, 9 ]; $VAR7 = '5'; $VAR8 = 6; # %$h4(ハッシュコンテキストで評価) $VAR1 = 'def'; $VAR2 = 4; $VAR3 = 'abc'; $VAR4 = 123; $VAR5 = 'ghi'; $VAR6 = [ 7, 8, 9 ]; $VAR7 = '5'; $VAR8 = 6; #--------------------- (b) # \%h3(リファレンス経由で評価) $VAR1 = { 'def' => 4, 'abc' => 123, 'ghi' => [ 7, 8, 9 ], '5' => 6 }; # $h4 $VAR1 = { 'def' => 4, 'abc' => 123, 'ghi' => [ 7, 8, 9 ], '5' => 6 };
見ての通り、コンテキストさえ合わせればどちらも同じ形式で扱えるようである。
my %h5 = ("abc" => 123, "def" => 456, "ghi" => 789); my $h6 = {"abc" => 123, "def" => 456, "ghi" => 789}; #--------------------- (a) print join(" ", @h5{"abc", "ghi"}), "\n"; print join(" ", @$h6{"def", "ghi"}), "\n"; #--------------------- (b) @h5{"ghi", "abc"} = @h5{"abc", "ghi"}; @$h6{"def", "abc"} = @$h6{"abc", "def"}; for my $key (sort(keys(%h5))) { print "[$key] = ", $h5{$key}, "\n"; } for my $key (sort(keys(%$h6))) { print "[$key] = ", $h6->{$key}, "\n"; } #--------------------- (c) @h5{"abc", "ghi"} = (undef, undef); @$h6{"abc", "def"} = (undef, undef); print Dumper(%h5), "\n"; print Dumper(%$h6), "\n"; #--------------------- (d) my %h7 = (); if(keys(%h7)) { print Dumper(%h7); } else { print "%h7 is empty.\n"; }
#--------------------- (a) 123 789 456 789 #--------------------- (b) # %h5 [abc] = 789 [def] = 456 [ghi] = 123 # $h6 [abc] = 456 [def] = 123 [ghi] = 789 #--------------------- (c) # %h5 $VAR1 = 'def'; $VAR2 = 456; $VAR3 = 'abc'; $VAR4 = undef; $VAR5 = 'ghi'; $VAR6 = undef; # $h6 $VAR1 = 'def'; $VAR2 = undef; $VAR3 = 'abc'; $VAR4 = undef; $VAR5 = 'ghi'; $VAR6 = 789; #--------------------- (d) %h7 is empty.
例:delete @hash_slice{'keyA', 'keyC'};