map
函数提供了一种将一系列值转换成另一系列值的方法。通常是一对一的转换,但是最后的结果也可以比原来的列表长或短一些。
我们在grep of Perl中已经看过类似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来检查值是否在列表中。也可以使用List::MoreUtils模块的any函数,但是如果使用hash来查找会有更好的可读性和更快的速度。
我们需要创建一个hash表,把数组的所有元素作为key,1作为值。然后,用一个简单的hash查找代替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
};
上面的代码,我们并不关心hash项的值,但是应该是Perl中的真值。
这种方案可以有效的避免对大集合的反复查找,小集合则可以使用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.