スライス
配列の添え字に「@arr[1,2,3]」のようにカンマ区切りで複数の数字を書くと、その配列の1番目、2番目、3番目の要素が入った新しい配列を得る事ができます。これを「スライス」と呼ぶそうです。「$arr[1]」と書く場合とは違い、返ってくるのが配列なので「@arr[1,2]」のように頭に「@」をつけます。
use strict;
# 0 1 2 3 4 5 6 7
my @arr = (1, 2, 4, 8, 16, 32, 64, 128);
print "@arr\n";
print "@arr[2,4,6]\n"; # 2, 4, 6 番目の要素
print "@arr[5..7]\n"; # 5 から 7 番目の要素
print "@arr[0,3..5]\n"; # 0 と 3 から 5 番目の要素
実行すると、
1 2 4 8 16 32 64 128 4 16 64 32 64 128 1 8 16 32
となります。添え字の「n..m」の意味については後述。
この「スライス」を利用すれば、先ほどの「localtime から月日を受け取るコード」が別の方法で書けそうです。
use strict;
my ($day, $month) = (localtime())[3,4];
print $month+1, "/", $day, "\n";
localtime() にカッコをつけて、リストコンテキストで評価してから、そのリストの 3 番目の要素(日)と 4 番目の要素(月)をスライスして、それを右辺としてリスト代入しています。
実行すると
5/30
と表示されました。(^_^)
また、スライスはハッシュに対しても行なう事ができます。複数のキーをカンマ区切りで指定してハッシュをスライスすると、その値の配列を得る事ができます。use strict している場合、スライスの時のキーにはダブルクォテーションが必要なので注意しましょう。
use strict;
our %letter_names = (
A => 'Alpha', B => 'Bravo', C => 'Charlie', D => 'Delta',
E => 'Echo', F => 'Foxtrot', G => 'Golf', H => 'Hotel',
I => 'India', J => 'Juliet', K => 'Kilo', L => 'Lima',
M => 'Mike', N => 'November', O => 'Oscar', P => 'Papa',
Q => 'Queen', R => 'Romeo', S => 'Sierra', T => 'Tango',
U => 'Uniform', V => 'Victor', W => 'Whiskey', X => 'Xray',
Y => 'Yankee', Z => 'Zulu',
);
print "PALMO: @letter_names{'P', 'A', 'L', 'M', 'O'}\n";
print "PERL: @letter_names{'P', 'E', 'R', 'L'}\n";
print "BANANA: @letter_names{'B', 'A', 'N', 'A', 'N', 'A'}\n";
%letter_names は、英単語のスペルを伝える時にアルファベットに対してよく使われる英単語のハッシュテーブルです。スライスを利用して英単語のスペルを説明しています。
実行結果は以下の通りです。
PALMO: Papa Alpha Lima Mike Oscar PERL: Papa Echo Romeo Lima BANANA: Bravo Alpha November Alpha November Alpha
スライスのお陰でとても楽チンです。スライスを使わないとちょっと面倒かも。
また、こんな関数を作れば、わざわざコンマで区切らなくても表示できますね。
sub tell_word {
my $word = uc(shift);
my @letters = split //, $word;
print "$word: @letter_names{@letters}\n";
}
tell_word("study"); # STUDY: Sierra Tango Uniform Delta Yankee
tell_word("Larry"); # LARRY: Lima Alpha Romeo Romeo Yankee
uc を使うと、文字列を全て大文字にできます。ちなみに小文字にする場合は lc です。
また、split は第1引数に渡した正規表現を区切り文字として、第2引数の文字列を区切って、配列に分解する関数です。空パターン(//)を渡すと、文字列を1文字ずつ区切った配列を返してくれます。(split //, "ABCD" → ("A", "B", "C", "D"))
この配列をスライスの添え字に使う事で、英単語のスペルを説明しているわけです。(^_^)
スライスはとても便利ですね。D言語で見たことがありますが、言語の構文として組み込まれているのは結構めずらしいのではないでしょうか。
範囲構文
スライスの解説の中で、添え字として「n..m」のように書いていますが、これは「nからmの数字」を列挙する為の構文です。例えば「2..6」と書いた場合「2,3,4,5,6」と書いたのと同じ意味です。
この構文を利用すると、「n から m の数字のリスト」を簡単に作れます。また、for 文に利用すれば「n から m のそれぞれの数字に対する処理」も簡単に書けてしまいます。
use strict;
# 3 から 8 の数字を表示
my @numbers = (3..8);
print "@numbers\n";
# 5 から 10 の2乗をそれぞれ表示
for (5..10) { print $_ * $_, " " }
実行結果は以下の通り。
3 4 5 6 7 8 25 36 49 64 81 100
この省略記法もとても便利ですね。
ただ、過度の省略はコードが読みづらくなってしまうので、心配な点でもあります。Perl はよく「他人の書いたコードが読みづらい」と評されるそうですが、こういった省略に原因があるのかも。
でも、人に読みやすいコードを書くのはとっても難しいですし、ましてや TIMTOWTDI な Perl ではなおさらです。その辺りのバランスを見極めつつ、読みやすいコードが書ければいいな、と思います。(^_^)