Perl 多命令 grep 与 $_

con*_*con 3 perl grep

我正在努力更好地学习 Perl grep

我想 grep 哈希的哪些键不在数组

my %args = ( fake => 1);
my @defined_args = ('color', 'colors', 'data', 'figheight', 'figwidth', 'filename', 'flip', 'grid', 'labelsize', 'logscale', 'minor_gridlines');
my @bad_args = grep { not grep {$_} @defined_args} keys %args;
Run Code Online (Sandbox Code Playgroud)

@bad_args 最后一行中的坏参数列表显然是错误的。

我知道我可以用哈希做同样的事情,但我希望能够用多阶 grep 来做到这一点,即 grep on grep 。

我怎样才能像下面这样做到这一点?

my @bad_args = grep { not grep {$_ eq $_} @defined_args} keys %args;
Run Code Online (Sandbox Code Playgroud)

我很困惑,因为会有两个$_,我无法对其进行相等测试。

zdi*_*dim 10

首先是直接的答案——那个块grep,你可以在里面放入任何代码。这就是该块的要点,元素的传递/不传递基于最后返回的语句的真实性。

my @bad_args = grep { 
    my $key = $_; 
    @defined_args == grep { $key ne $_ } @defined_args
} keys %args;
Run Code Online (Sandbox Code Playgroud)

这里我们测试一个键是否不等于数组元素,然后测试它是否不等于所有元素,由什么决定。另一种方法是测试它是否等于任何一个元素,

not grep { $key eq $_ } @defined_args;
Run Code Online (Sandbox Code Playgroud)

这有点复杂,需要使用否定。

但这些都是常见的事情,而且还有图书馆。

直接改进上述

use List::Util 1.33 qw(none);  # before 1.33 it was in List::MoreUtils

my @bad_args = grep { 
    my $key = $_; 
    none { $key eq $_ } @defined_args 
} keys %args;
Run Code Online (Sandbox Code Playgroud)

现在,所需的“负数”已被吸收到库的函数名称中,这使得它更容易查看。此外,none一旦发现失败就会停止,同时grep始终处理所有元素,因此这也更有效。

与基于散列的方法(复杂度O(NM-M 2 /2)左右)相比,这些方法的效率不是很高,但这对于小型数组来说完全无关。问题中提到的使用哈希值来处理与存在相关的问题是一个标准;例如,请参阅 这篇文章,或下面讨论的所有库中使用的方法的来源(最简单的示例)。


最后,虽然问题是关于(双重)过滤,但应该提到的是,我们正在寻找列表中的哪些元素不在另一个列表中;列表之间的“差异”。然后其他类型的库就开始发挥作用。一些例子

使用Set::Scalar

use Set::Scalar;
...

my $keys = Set::Scalar->new(keys %args);
my $good = Set::Scalar->new(@defined_args);

my $keys_not_in_good = $keys->difference($good);
say $keys_not_in_good;
Run Code Online (Sandbox Code Playgroud)

另请注意Set::Object在同一阵营中。

还有专门用于数组比较的工具,例如List::Compare

use List::Compare;
...

my $lc = List::Compare->new('-u', '-a', \@defined_args, [keys %args]);

my @only_in_second = $lc->get_complement();

say "@only_in_second";
Run Code Online (Sandbox Code Playgroud)

选项-u-a展示一些模块功能,以加快速度;他们没有必要。这个模块有很多,请参阅文档。另一端是简单的Array::Utils

还有更多。例如,请参阅此页面以获取大量想法。