2013-11-25 80 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

相關問題