map()で少しはまった
map()について少しはまったのでメモ。
AI_1 UEO_1 AI_2 UEO_2 AI_3 UEO_3.....
上記のような要素が入った配列を作成したい。
で、初めは以下のように考えた。
my @array = map { "AI_$_", "UEO_$_" } 1 .. 10; print "@array\n";
しかしこれではsyntax errorとなる。
% ./48test.pl syntax error at 48test.pl line 5, near "} 1"
?、展開させてるのが悪いのかなと思って、以下のようにしてみた。
my @array = map { "AI_".$_, "UEO_".$_ } 1 .. 10; print "@array\n";
AI_1 UEO_1 AI_2 UEO_2 AI_3 UEO_3.....
できた。
とはいえ、このままだと気持ち悪いので、マニュアルを読んでみる。
perldoc -f map
map BLOCK LIST
map EXPR,LIST
.........
"{" starts both hash references and blocks, so "map { ..." could be either the start of
map BLOCK LIST or map EXPR, LIST. Because perl doesn’t look ahead for the closing "}"
it has to take a guess at which its dealing with based what it finds just after the
"{". Usually it gets it right, but if it doesn’t it won’t realize something is wrong
until it gets to the "}" and encounters the missing (or unexpected) comma. The syntax
error will be reported close to the "}" but you’ll need to change something near the
"{" such as using a unary "+" to give perl some help:%hash = map { "\L$_", 1 } @array # perl guesses EXPR. wrong
%hash = map { +"\L$_", 1 } @array # perl guesses BLOCK. right
%hash = map { ("\L$_", 1) } @array # this also works
%hash = map { lc($_), 1 } @array # as does this.
%hash = map +( lc($_), 1 ), @array # this is EXPR and works!%hash = map ( lc($_), 1 ), @array # evaluates to (1, @array)
or to force an anon hash constructor use "+{"
@hashes = map +{ lc($_), 1 }, @array # EXPR, so needs , at end
and you get list of anonymous hashes each with only 1 entry.
{}の中がきちんとBLOCKとして評価されないとだめということか、な。
前述のは「{ "AIU_$_"」の部分でEXPR扱いだったんだな。
それを避けようと「{ "AI_$_", "UEO_$_" },」と最後にカンマを入れると更に無名ハッシュ扱いされると。
以上を踏まえて、以下の三つは望み通り動いた。
@array = map { +"AI_$_", "UEO_$_" } 1 .. 10; @array = map { ("AI_$_", "UEO_$_") } 1 .. 10; @array = map ( "AI_$_", "UEO_$_" ), 1 .. 10;