Perl smartmatch运算符或grep检查数组中是否存在值

Perl smartmatch运算符或grep检查数组中是否存在值,perl,Perl,在阅读了最近关于检查数组中是否存在值的Perl问题后,我开始思考如何执行此操作。我看到大多数人在表格中推荐grep选项 if (!grep { $input_day eq $_ } @days ) { say "Grep Invalid Day"; } 然而,当我读到这个问题时,我的第一个问题跳到了智能匹配操作符 unless ( $input_day ~~ @days ) { say "Smart Invalid Day"; } 所以我想知道使用grep是否比smart-m

在阅读了最近关于检查数组中是否存在值的Perl问题后,我开始思考如何执行此操作。我看到大多数人在表格中推荐grep选项

if (!grep { $input_day eq $_ } @days ) {
    say "Grep Invalid Day";
}
然而,当我读到这个问题时,我的第一个问题跳到了智能匹配操作符

unless ( $input_day ~~ @days ) {
    say "Smart Invalid Day";
}
所以我想知道使用grep是否比smart-match有好处,反之亦然。我知道smart match只在更高版本的Perl中可用,因此对于使用5.10.1之前的Perl版本的人来说,这并不是什么值得推荐的东西

我以前从来没有真正的标杆Perl代码,所以下面的代码是从一个在线示例编写的。我试着运行智能匹配示例200万次,运行grep示例200万次,并记录计时

use strict;
use warnings;
use v5.16.2;
use Benchmark;

my $input_day = shift;
my @days = qw /mon tue wed thu fri sat sun/;

my $smart_test_start = new Benchmark();
for(my $x=0; $x<10000000; $x++){
        unless ( $input_day ~~ @days ) {
                #here we would execute some code
        }
}
my $smart_test_end = new Benchmark();

my $grep_test_start = new Benchmark();
for(my $y=0; $y<10000000; $y++){
        if (!grep { $input_day eq $_ } @days ) {
                #here we would execute some code
        }
}
my $grep_test_end = new Benchmark();

my $smart_diff = timediff($smart_test_end, $smart_test_start);
my $grep_diff = timediff($grep_test_end, $grep_test_start);

say "SMART: ", timestr($smart_diff,'all');
say "GREP: ", timestr($grep_diff,'all');
输入“thu”

输入“sun”

输入“非”

在所有情况下,智能匹配操作符的性能似乎都优于grep。查看结果,我假设在早期用例中,这是因为智能匹配将在找到匹配后立即停止,而grep将在匹配第一次出现后继续检查数组的其余部分

然后我看到其他人建议使用某些模块来查找第一个实例等


人们不推荐智能匹配操作员有什么原因吗?智能匹配是否存在某些限制或不可靠性?

请勿,重复请勿在生产代码中使用智能匹配运算符。根据smartmatch已标记为实验性:

Smart match在v5.10.0中添加,并在v5.10.1中进行了重大修改,这一直是一个常见的投诉点。尽管有许多方法可以使用它,但对于Perl的用户和实现者来说,它也被证明是有问题和令人困惑的。关于如何最好地解决这一问题,已经提出了一些建议。很明显,smartmatch几乎肯定会在未来改变或消失。不建议依赖其当前行为

当解析器看到~~、给定或出现错误时,将发出警告。要禁用这些警告,可以将此行添加到适当的范围:

但是,请考虑替换这些功能的使用,因为它们可能会在变得稳定之前再次改变行为


这意味着,在这些问题得到解决之前,依赖于此功能的代码不能被视为稳定的。

不要,重复不要在生产代码中使用smartmatch操作符。根据smartmatch已标记为实验性:

Smart match在v5.10.0中添加,并在v5.10.1中进行了重大修改,这一直是一个常见的投诉点。尽管有许多方法可以使用它,但对于Perl的用户和实现者来说,它也被证明是有问题和令人困惑的。关于如何最好地解决这一问题,已经提出了一些建议。很明显,smartmatch几乎肯定会在未来改变或消失。不建议依赖其当前行为

当解析器看到~~、给定或出现错误时,将发出警告。要禁用这些警告,可以将此行添加到适当的范围:

但是,请考虑替换这些功能的使用,因为它们可能会在变得稳定之前再次改变行为


这意味着,在这些问题得到解决之前,依赖于此功能的代码不能被认为是稳定的。

正确的解决方案是使用哈希而不是数组

my %days = map { $_ => 1 } @days
然后你就可以写了

unless ($days{$input_day}) {
  say "Hash Invalid Day";
}
而且性能将远远超过任何其他解决方案


(我希望这是显而易见的,但是您应该只设置一次哈希,并在以后的所有测试中继续使用它。)

正确的解决方案是使用哈希而不是数组

my %days = map { $_ => 1 } @days
然后你就可以写了

unless ($days{$input_day}) {
  say "Hash Invalid Day";
}
而且性能将远远超过任何其他解决方案


(我希望这是显而易见的,但您应该只设置一次哈希,并在以后的所有测试中继续使用它。)

希望添加我的经验,因为我做了一些测试。我一直使用Smart Match,最近厌倦了它会产生的警告

我有一个1亿的文本文件,10个字符串

Perl脚本将STDIN转换为数组,并使用3种常见方法查找数组中是否存在字符串。我尝试使用上面建议的哈希映射,但是哈希映射的生成时间是数组的3倍。如果您正在对现有值进行广泛的测试,那么在某一点上这种折衷可能是可行的,因为哈希上的exists检查基本上是即时的。它还将取决于您的数据源

在未来,我计划主要使用List::Util(any),因为它是一个核心模块,性能非常可靠

#!/usr/bin/perl
use List::Util qw(any);
my @arr = qw(a b c d e);
if ( any { $_ eq 'd' } @arr ) { 
    print "Found.\n";
}
方法:

List::Util (any): if ( any { $_ eq $a } @arr ) { do something. }
Perl Smartmatch: if ( $b ~~ @arr ) { do something. }
Grep: if ( grep { $c eq $_ } @arr ) { do something. }
我搜索了我知道存在于1,10100100010000100001000001000000001000000001000000001000000000位置的值。计时是通过Time::HiRes模块完成的

我发现,如果大多数值位于数组的开头,smartmatch将执行List::Utils方法。但是,如果你的值大部分在中间或结尾,或者不存在于数组列表中:Util将执行。grep似乎做了一次彻底的搜索,不管它是否找到了一个值

更多输出详细信息:

Smart Match total: 5.939 seconds.
List::Util::any: 7.332 seconds.
Grep total: 39.553 seconds.
阵列生成时间:30.315秒。
正在搜索100000000个arr元素。

任何搜索eavTa2eWr1
找到任何-eavTa2eWr1。
时间:0.540秒。
任何搜索mhEusMj5E7
任何发现-mhEusMj5E7。
时间:0.358秒。
任何搜索WGwHfJICK6
任何发现-WGWFJICK6。
时间:0.364秒。
任何搜索I48fNDYNKF
任何发现-I48fNDYNKF。
时间:0.359秒。
任何搜索q3YVBTmX9J
找到任何-q3YVBTmX9J。
时间:0.357秒。
任何搜索pw0J5vRCnW
任何发现-pw0J5vRCnW。
时间:0.358秒。
任何搜索GNJP5flX5z
找到任何-GNJP5flX5z。
时间:0.392秒。
任何搜索3
#!/usr/bin/perl
use List::Util qw(any);
my @arr = qw(a b c d e);
if ( any { $_ eq 'd' } @arr ) { 
    print "Found.\n";
}
List::Util (any): if ( any { $_ eq $a } @arr ) { do something. }
Perl Smartmatch: if ( $b ~~ @arr ) { do something. }
Grep: if ( grep { $c eq $_ } @arr ) { do something. }
Smart Match total: 5.939 seconds.
List::Util::any: 7.332 seconds.
Grep total: 39.553 seconds.
List::Util::any: 28.980 seconds.
Grep total: 34.790 seconds.
Smart Match total: 42.913 seconds.