map 函式提供的一個簡單的方法可以把一個串列轉換成另一個串列。通常這種方法是一對一的轉換,不過最後的串列可能比原本的串列要來的短或是來的長, 這兩種都有可能。

Perl 的 grep 是 UNIX 指令中 grep 的通式。它從原本串列中選出所要的元素,然後傳回這些元素,而不改變它們的值。

map 則是用來改變這些原本元素的值。

這兩各函式語法是類似的。你提供一段程式碼以及串列值,然後回傳串列值。原本串列的值則放在 $_ 裡, Perl 預設變數 ,然後執行程式碼。回傳值則被傳到左邊的變數。

使用 map 來做簡單的轉換

my @numbers = (1..5);
print "@numbers\n";       # 1 2 3 4 5
my @doubles = map {$_ * 2} @numbers;
print "@doubles\n";       # 2 4 6 8 10

建立一個快速的查看表

有時候我們想要知道某一串列是否位在給定的串列中。我們可以使用 grep 來檢查。甚至我們可以使用 any 這個函式,來自 List::MoreUtils。如果我們使用雜湊方式來查看的話,使用 map 可讀性比較好而且更快。

我們需要先建立一個雜湊表,它的鍵值就是陣列的元素,而雜湊的值都是 1s。這個簡單的雜湊表可以代替 grep

use Data::Dumper qw(Dumper);

my @names = qw(Foo Bar Baz);
my %is_invited = map {$_ => 1} @names;

my $visitor = <STDIN>;
chomp $visitor;

if ($is_invited{$visitor}) {
   print "The visitor $visitor was invited\n";
}

print Dumper \%is_invited;

下面是 Dumper 輸出的結果:

$VAR1 = {
          'Bar' => 1,
          'Baz' => 1,
          'Foo' => 1
        };

在這個方法中我們不在意雜湊的值,只要它們都為真就好。

這個方法只有在你有很大的資料才比較有用。(所謂很大的資料要看你的系統而定。) 否則 any 或是 grep 就很好用了。

從上面的例子中,map 回傳兩個值:一個是原本陣列的元素,一個是 1。

my @names = qw(Foo Bar Baz);
my @invited = map {$_ => 1} @names;
print "@invited\n"

會印出:

Foo 1 Bar 1 Baz 1

胖箭頭(=>)

=> 叫作 胖箭頭 或是 胖逗號。它基本上跟逗號的意義差不多,不過有個例外,不在這裡描述,請見 Perl hashes

map 中複雜的表示式

你可以 map 中使用複雜的表示式:

my @names = qw(Foo Bar Baz);
my @invited = map { $_ =~ /^F/ ? ($_ => 1) : () } @names;
print "@invited\n"

上面會印出

Foo 1

在這個程式區段中,我們使用三元運算子來回傳一對串列或是空串列。很明顯地,我們選擇只要以 "F" 開頭的人名。

$_ =~ /^F/ ? ($_ => 1) : ()

perldoc

要做更進一步的了解,請看 perldoc -f map