2013-11-25 41 views
0

在阅读了关于检查数组中是否存在值的最新Perl问题之后,让我想到了如何执行此操作。我看大多数人的形式推荐grep的选项Perl智能匹配运算符或grep检查数组中是否存在值

if (!grep { $input_day eq $_ } @days) { 
    say "Grep Invalid Day"; 
} 

然而,当我读到这个问题,我首先通过跃升为智能匹配运营商

unless ($input_day ~~ @days) { 
    say "Smart Invalid Day"; 
} 

所以这让我不知道是否有任何好处在智能匹配上使用grep,反之亦然。我知道智能匹配只能在更高版本的Perl中使用,因此不适用于5.10.1之前版本的Perl。

我从来没有真正用过Benchmark Perl代码,所以下面的代码是从一个在线例子中编写的。我曾尝试运行200万次智能匹配示例和200万次grep示例并记录时间。

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'); 

我使用了几个不同的输入。

输入 “星期一”

SMART: 3 wallclock secs (2.75 usr 0.00 sys + 0.00 cusr 0.00 csys = 2.75 CPU) 
GREP: 12 wallclock secs (12.02 usr 0.01 sys + 0.00 cusr 0.00 csys = 12.03 CPU) 

输入 “周四”

SMART: 6 wallclock secs (5.67 usr 0.00 sys + 0.00 cusr 0.00 csys = 5.67 CPU) 
GREP: 11 wallclock secs (11.46 usr 0.01 sys + 0.00 cusr 0.00 csys = 11.47 CPU) 

输入 “晒”

SMART: 8 wallclock secs (8.87 usr 0.01 sys + 0.00 cusr 0.00 csys = 8.88 CPU) 
GREP: 12 wallclock secs (11.62 usr 0.00 sys + 0.00 cusr 0.00 csys = 11.62 CPU) 

输入 “非”

SMART: 9 wallclock secs (8.46 usr 0.00 sys + 0.00 cusr 0.00 csys = 8.46 CPU) 
GREP: 11 wallclock secs (11.58 usr 0.13 sys + 0.00 cusr 0.00 csys = 11.71 CPU) 

在所有情况下,智能匹配运算符似乎比grep执行得更好。看看结果,我假设在早期使用情况下,这是因为智能匹配一旦发现匹配就会停止,因为在匹配第一个匹配项后,grep将继续检查数组的其余部分。

我再看看其他人推荐使用某些模块找到的第一个实例等

是否有某种原因,人们不建议智能匹配运营商?智能匹配有限制还是不可靠?

+0

你也应该考虑从'['名单:: MoreUtils'] any'(HTTPS ://metacpan.org/pod/List :: MoreUtils) – Borodin

回答

2

请勿重复请勿在生产代码中使用smartmatch操作符。据perldelta smartmatch已被标记实验:

智能匹配,在v5.10.0添加和v5.10.1显著修订后,一直申诉的正规点。虽然有很多方法是有用的,但它也证明了Perl的用户和实现者有问题和困惑。关于如何最好地解决这个问题已经有了一些建议。很明显,smartmatch几乎肯定会在未来发生变化或消失。不建议依靠其当前行为。

当解析器看到~~,给定或什么时候,会发出警告。要禁用这些警告,您可以将此行添加到适当范围:

no if $] >= 5.018, "experimental::smartmatch"; 

考虑,不过,在更换使用这些功能,因为它们可能会成为稳定之前再次改变人们的行为。

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

+0

[This](https://metacpan.org/pod/release/RJBS/perl-5.18.0/pod/perldelta.pod#The-smartmatch-family功能 - 现在 - 实验)是你想要的部分。 – Borodin

+0

@ysth链接是正确的,只是抹黑了错误的东西。我想,当我写这篇文章的时候分心了。 –

+0

“取决于此功能的代码不能被视为稳定”*如果*您希望最终升级到perl 5.22或更高版本。 (如果基本的$ string ~~ @array_of_strings案件受到任何改变而没有完全移除~~,并且非常惊讶,如果它最终被移除,如果它早于5.24发生,我会感到惊讶。) – ysth

2

妥善解决这个使用哈希不是数组

my %days = map { $_ => 1 } @days 

,那么你可以写

unless ($days{$input_day}) { 
    say "Hash Invalid Day"; 
} 

和性能将远远超过任何其他解决方案。

(我希望这是显而易见的,但你应该建立哈希只有一次,此后继续使用它的所有测试。)

+0

@woolstar:为什么? – Borodin

+0

@woolstar:此外,这应该是正确的@days {@days} =()' – Borodin

+0

它最终使用较少的内存为大型数据集,因为它不必为每个条目分配一个“值”。 undef是没有存储开销的内在魔力。 – woolstar

相关问题