読者です 読者をやめる 読者になる 読者になる

Perl日記

PerlとかRubyとかPHPとかPythonとか

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;