代码:
@all_matches = grep
{
! ( $seensentence
{
$_->[0] .'-'. $_->[1] .'-'. $_->[5]
}
++ )
}
@all_matches;
目的:此代码会删除数组@all_matches
中某些元素的重复项。
我完全崩溃的尝试(在......我不确定的地方......)
Grep返回返回true的@all_matches
元素。
哈希%seensentence
的关键是三个元素? @all_matches
。由于哈希只能有唯一键,因此第一次通过它的值从undef(0)递增到1.下一次,它是一个定义的值,但!
表示grep只返回它undef(与该元素相关的唯一值)。
我的问题:
(1)如何将{$_->[0] .'-'. $_->[1] .'-'. $_->[5]}++
变成HoH?
我被告知这是实现它的另一种(惯用的)方式。在黑暗中刺伤将是:
( {$_->[0] => 0,
$_->[1] => 0,
$_->[5] => 0} )++
(1b)因为我不明白原作是如何做我想要的。我读到-bareword
等同于"-bareword"
,所以我尝试了{"$_->[0]" . "$_->[1]". "$_->[5]"}
,它似乎完全相同。我仍然不明白:它是将每个元素分别视为一个键(a)(如一个键数组)还是(b)正确:所有同时(因为.
将它们连接成一个字符串)或是(c)不按我认为的那样做?
(2)这是什么意思:$_->[0] || $_->[1] || $_->[5]
?它与上面的内容不同。
我读到:短路逻辑运算符返回最后一个值,所以它会检查{$_->[0]}
处的值,如果有一个值,我认为那里的值会增加,如果没有,它会检查下一个元素,直到没有为真,这是当grep传递唯一值时。
感谢您的时间,我尽量做到尽可能彻底(对于错误?)但是如果有任何遗漏,请告诉我。
答案 0 :(得分:5)
首先让我们将grep
转换为foreach
循环,以便我们可以更清楚地检查它。为了清楚起见,我将把一些习语扩展成更大的构造。
my @all_matches = ( ... );
{
my %seen;
my @no_dupes;
foreach my $match ( @all_matches ) {
my $first_item = $match->[0];
my $second_item = $match->[1];
my $third_item = $match->[5];
my $key = join '-', $first_item, $second_item, $third_item;
if( not $seen{ $key }++ ) {
push @no_dupes, $match;
}
}
@all_matches = @no_dupes;
}
换句话说,原始编码器使用$ match中保存的数组引用为$match->[0]
,1
和5
的每个引用索引创建哈希键。由于散列键是唯一的,因此在推入@no_dupes
之前检查密钥是否已存在,将删除任何重复项。
grep{}
机制只是一个更有效的代码(即,更快的类型,没有一次性变量)成语来完成同样的事情。如果它有效,为什么要重构呢?你需要改进的是什么不做?
要对HoH做同样的事情,你可以这样做:
my @all_matches = ( ... );
{
my %seen;
my @no_dupes;
foreach my $match ( @all_matches ) {
my $first_item = $match->[0];
my $second_item = $match->[1];
my $third_item = $match->[5];
if( not $seen{ $first_item }->{ $second_item }->{ $third_item }++ ) {
push @no_dupes, $match;
}
}
@all_matches = @no_dupes;
}
可以将其翻译成grep,如下所示:
my @all_matches = ( ... );
{
my %seen;
@all_matches = grep { not $seen{$_->[0]}->{$_->[1]}{$_->[5]}++ } @all_matches;
}
但是,在这种情况下,我没有看到构建数据结构的明显优势,除非您打算稍后使用%seen
来做其他事情。
对于||
运算符,这是一种不同的动物。我想不出在这种情况下使用它的任何有用方法。例如,“$a || $b || $c
”的逻辑短路运算符测试$a
的布尔真值。如果是,则返回其值。如果它是假的,它会以同样的方式检查$b
。如果它是假的,它会以同样的方式检查$c
。但如果$a
为真,则永远不会检查$b
。如果$b
为真,则永远不会检查$c
。
答案 1 :(得分:4)
$ seensentence的关键是一个简单的字符串。表达式$_->[0] .'-'. $_->[1] .'-'. $_->[5]
构造一个字符串。这是一个等价的表达式:join '-', $_->[0], $_->[1], $_->[5]
。它似乎假设元素0,1和5足以识别@all_matches中的重复项。
修改强>
错过了你的上一个问题。
$_->[0] || $_->[1] || $_->[5]
返回
$_->[0]
如果$_->[0]
不为假(0,空字符串,未定义),$_->[1]
如果$_->[1]
不是假,$_->[5]
否则。一旦有意义停止,快捷操作员就会停止。在||
的情况下,只要结果是某个非假值,就会出现这种情况。在&&
的情况下,只要结果为假,就会这样。