从模块MoreUtils.pm解释Perl的语法

A.G*_*ast 1 perl

我正在寻求从模块MoreUtils.pm解释Perl的uniq和fidrstidx函数的语法.

在寻找之后,我已经知道了从具有重复元素的数组中获取uniq数组元素并通过以下方式从数组中查找第一个索引的其他方法:

## remove duplicate elements ##

my @arr = qw (2 4 2 8 3 4 6);
my @uniq = ();
my %hash = ();
@uniq = grep {!$hash{$_}++ } @arr;

### first index ###

@arr = qw (Java ooperl Ruby cgiperl Python);
my ($index) = grep {$arr[$_] =~ /perl/} 0..$#arr;
Run Code Online (Sandbox Code Playgroud)

任何人都可以解释我下面这个sub uniq函数的第二行,包括来自MoreUtils.pm的map和ternary运算符:

 map {$h{$_}++ == 0 ? $_ : () } @;
Run Code Online (Sandbox Code Playgroud)

并且

&@传递给firstidx函数和函数体中的下一行:

 local *_ = \$_[$i];
Run Code Online (Sandbox Code Playgroud)

据我所知,sub例程ref被传递给firstidx.但是更加详细的解释将非常感激.

谢谢.

bri*_*foy 8

您的第二个问题在评论中得到了回答.

您的第一个问题是map {$h{$_}++ == 0 ? $_ : () } @;List :: MoreUtils询问.在最近的版本中,它实际上在List::MoreUtils::PP(对于Pure Perl),因为许多子例程也在C和XS中实现.这是Pure Perl的当前版本uniq:

sub uniq (@)
{
    my %seen = ();
    my $k;
    my $seen_undef;
    grep { defined $_ ? not $seen{ $k = $_ }++ : not $seen_undef++ } @_;
}
Run Code Online (Sandbox Code Playgroud)

map虽然它正在使用,但它具有相同的技术grep.将grep通过所有的元素的进入@_,并必须返回true或false为他们每个人.评估为true的元素最终会出现在输出列表中.然后,代码想要在第一次看到它时将元素求值为true,并在其余时间做出错误.

在此代码中,它undef单独处理.如果当前元素不是undef,则它执行条件运算符的第一个分支,否则执行第二个分支.现在让我们来看看分支机构.

定义的大小写为哈希添加了一个元素.没有人留下关于使用的代码评论,$k但它可能与不干扰有关$_.这$k成为哈希的关键:

 not $seen{ $k = $_ }++
Run Code Online (Sandbox Code Playgroud)

如果这是第一次遇到密钥,则哈希值为undef.在使用该值之后,该后增量会起作用,因此暂时不要考虑这一点.低优先级not看到了价值$seen{$k},即undef.在not原来的假值undef成真.这是真的表明这是第一次grep看到$_.它成为输出列表的一部分.然后它++完成它的工作并将undef值递增到1.在具有相同值的所有后续遭遇中,哈希值将为真.该not会变成真正的价值为假,该元素不会在输出列表.

map告诉你实现grep.它在条件为true时返回一个元素,在false为false时不返回任何元素:

map {$h{$_}++ == 0 ? $_ : () } @_;
Run Code Online (Sandbox Code Playgroud)

对于每个元素,它将其添加为哈希中的键,并将该值与0进行比较.第一次看到一个元素值为undef.在数值上下文中undef0.因此,==返回true并且条件运算符的第一个分支将触发,返回$_到输出列表.该++然后从递增的散列值undef1.下次遇到相同的值时,哈希值不会,0并且条件运算符的第二个分支返回空列表.这不会在输出列表中添加任何元素.