用Perl编写的Perl中的map
函数是什么?我只是无法弄清楚如何实现它。这是我的尝试:
use Data::Dumper;
sub Map {
my ($function, $sequence) = @_;
my @result;
foreach my $item (@$sequence) {
my $_ = $item;
push @result, $function->($item);
}
return @result
}
my @sample = qw(1 2 3 4 5);
print Dumper Map(sub { $_ * $_ }, \@sample);
print Dumper map({ $_ * $_ } @sample);
$_
中的{p> $function
未定义,但map
如何克服此问题?
答案 0 :(得分:10)
map
有一些特殊的语法,所以你不能在pure-perl中完全实现它,但这会非常接近它(只要你使用map的块形式): / p>
sub Map(&@) {
my ($function, @sequence) = @_;
my @result;
foreach my $item (@sequence) {
local $_ = $item;
push @result, $function->($item);
}
return @result
}
use Data::Dumper;
my @sample = qw(1 2 3 4 5);
print Dumper Map { $_ * $_ } @sample;
print Dumper map { $_ * $_ } @sample;
使用$_
代替local $_
可以克服 my $_
未定义的问题。实际上你几乎不想使用my $_
(即使你确实想在几乎所有其他变量上使用它)。
添加(&@)
原型允许您不要在块前面指定sub
。同样,你几乎never want to use prototypes,但这是对他们的有效使用。
答案 1 :(得分:5)
虽然接受的答案实现了类似map
的函数,但它不会像perl那样执行。 for
,foreach
,map
和grep
的一个重要部分是它们为您提供的$_
始终是参数中值的别名名单。这意味着在任何这些构造中调用s/a/b/
之类的东西将修改它们被调用的元素。这允许您编写如下内容:
my ($x, $y) = qw(foo bar);
$_ .= '!' for $x, $y;
say "$x $y"; # foo! bar!
map {s/$/!!!/} $x, $y;
say "$x $y"; # foo!!!! bar!!!!
因为在你的问题中,你曾要求Map
使用数组引用而不是数组,这里有一个适用于数组引用的版本,它与内置map
一样接近你可以得到的纯粹的Perl。
use 5.010;
use warnings;
use strict;
sub Map (&\@) {
my ($code, $array) = splice @_;
my @return;
push @return, &$code for @$array;
@return
}
my @sample = qw(1 2 3 4 5);
say join ', ' => Map { $_ * $_ } @sample; # 1, 4, 9, 16, 25
say join ', ' => map { $_ * $_ } @sample; # 1, 4, 9, 16, 25
在Map
中,(&\@)
原型告诉perl Map
裸字将使用与通常子例程不同的规则进行解析。 &
表示第一个参数将是一个裸块Map {...} NEXT
,或者它将是一个文字代码引用Map \&somesub, NEXT
。请注意后一版本中的参数之间的逗号。 \@
原型表明下一个参数将以@
开头,并将作为数组引用传入。
最后,splice @_
行会清空@_
,而不仅仅是复制值。这样,&$code
行会看到空@_
而不是收到的Map
。 &$code
的原因是它是调用子例程的最快方法,并且与map
使用的多字符调用样式非常接近,因为您可以在不使用C的情况下使用。这种调用样式非常适合对于这种用法,因为块的参数在$_
中,不需要任何堆栈操作。
在上面的代码中,我做了一点作弊,让for
完成本地化$_
的工作。这对性能有好处,但是为了看它是如何工作的,这里是重写的那一行:
for my $i (0 .. $#$array) { # for each index
local *_ = \$$array[$i]; # install alias into $_
push @return, &$code;
}
答案 2 :(得分:0)
我的Object::Iterate模块就是您要做的事情的一个示例。