在 Perl 中,grep
and都map
接受一个表达式和一个列表,并为列表中的每个元素计算表达式。
两者有什么区别?
grep
返回原始列表中与表达式匹配的元素,同时map
返回应用于原始列表每个元素的表达式的结果。
$ perl -le 'print join " ", grep $_ & 1, (1, 2, 3, 4, 5)'
1 3 5
$ perl -le 'print join " ", map $_ & 1, (1, 2, 3, 4, 5)'
1 0 1 0 1
第一个示例打印列表的所有奇数元素,而第二个示例根据相应元素是否为奇数打印 0 或 1。
我发现以最一般的形式思考grep()
和思考是有帮助的:map()
grep {BLOCK} LIST
map {BLOCK} LIST
grep()
是一个过滤器:它返回 LIST 中 BLOCK 返回 true 的项目子集。
map()
是一个映射函数:将一个值从 LIST 发送到 BLOCK,BLOCK 返回一个包含 0 个或多个值的列表;所有这些对 BLOCK 的调用的组合集将是返回的最终列表map()
。
map
将函数应用于列表中的所有元素并返回结果。
grep
返回列表中的所有元素,当函数应用于它们时,它们的计算结果为 true。
my %fruits = (
banana => {
color => 'yellow',
price => 0.79,
grams => 200
},
cherry => {
color => 'red',
price => 0.02,
grams => 10
},
orange => {
color => 'orange',
price => 1.00,
grams => 225
}
);
my %red_fruits = map { $_ => $fruits{$_} }
grep { $fruits{$_}->{color} eq 'red' }
keys(%fruits);
my @prices = map { $fruits{$_}->{price} } keys(%fruits);
my @colors = map { $fruits{$_}->{color} } keys(%fruits);
my @grams = map { $fruits{$_}->{grams} } keys(%fruits);
# Print each fruit's name sorted by price lowest to highest:
foreach( sort { $fruits{$a}->{price} <=> $fruits{$b}->{price}} keys(%fruits) )
{
print "$_ costs $fruits{$_}->{price} each\n";
}# end foreach()
关于 的另一件事grep
:在标量上下文中,它告诉您找到了多少项目。如果您真的不想要第二个列表,但您确实想知道有多少特定种类的项目,这可能很有用。
my @numbers = qw/1 2 3 4 5 6/;
my @odd_numbers = grep { $_ & 1 } @numbers; # grep returns (1, 3, 5)
my $how_many_odd = grep { $_ & 1 } @numbers; # grep returns 3
编辑:由于 OP 在评论中询问,我应该说您可以map
以相同的方式在标量上下文中使用。关键不是这grep
两个中唯一一个可以做到这一点,而是有时用grep
.
将 grep 视为带有过滤器的映射。map 迭代并提供对每个项目做某事的机会。例如这两行是等价的:
my @copy = @original;
my @copy = map {$_} @original;
同样,这两个是等价的:
my @copy = grep {-f $_} @original;
@copy = ();
for (@original)
{
push @copy, $_ if -f $_;
}
grep 提供插入条件的能力,因此成为过滤器。
开玩笑:grep 给出它的块标量上下文,map 给出它的块列表上下文。(并且 BLOCK foreach LIST 给出了它的块无效上下文。)