2010-02-19 78 views
7

可能的方式:有條件地在列表中包含元素的最佳方式是什麼?

  1. 使用push

    my @list; 
    push @list, 'foo' if $foo; 
    push @list, 'bar' if $bar; 
    
  2. 使用conditional operator

    my @list = ( 
        $foo ? 'foo' :(),  
        $bar ? 'bar' :(),    
    ); 
    
  3. 使用x!! Boolean list squash operator

    my @list = ( 
        ('foo') x!! $foo, 
        ('bar') x!! $bar, 
    ); 
    

哪一個更好?爲什麼?

+2

只是一個側面說明,你不使用任何這些字符串變量引用的,是嗎?沒有'$ {$ list [0]}'?這只是看起來像一個哈希給我。 – 2010-02-19 12:12:24

+0

投票問題類型問題應該是CW。 – 2010-02-19 12:16:06

+0

@Chris:不,我只是爲了簡單而使用了字符串。 – 2010-02-19 12:29:58

回答

12

那麼,他們都做不同的事情。

然而,所有其他因素相同的情況,

push @list, 'foo' if $foo; 

是最直接傳達其意義的語句,所以它應是優選的。

如果你不得不停下來思考那些推測數組元素的操作簡單,那麼你做錯了什麼。

my @list = (
    $foo ? 'foo' :(), 
    $bar ? 'bar' :(), 
); 

可能是好的,如果這是其他地方正在進行的一些巨大的初始化的一部分。

我認爲使用

my @list = (
    ('foo') x!! $foo, 
    ('bar') x!! $bar, 
); 

表明,程序員有— 我怎麼可以把這個?issues

順便說一下,沒有這種東西叫x!!複合算子。 !!double logical negation。它將任意虛假值轉換爲已定義但錯誤的值(空字符串),在使用perl時,會產生0數字。一個真實值被轉換爲1。這裏,!!$foo$bar上運行,並且編寫它x!! $foo不必要地混淆了代碼的含義。

xrepetition operator。所以,

('foo') x !!$foo; 

意味着重複('foo')一次或根本沒有,這取決於是否$foo分別爲真或假。

PS:當然,事實證明有一個PerlMonks article引入了所謂的布爾列表擠壓運算符。我讀了article,發現它不能令人信服。

+2

同意,'x !!'對我來說有點太聰明瞭。我希望它不會成爲一個慣用語。 – 2010-02-19 13:25:31

+0

實際上'!!'將一個假值轉換爲零長度的字符串。 – 2010-02-20 15:27:12

+0

@Brad在'perl'需要一個數字的地方使用時產生'0'。現在修復。謝謝。 – 2010-02-20 16:40:45

5

我想建議我拿什麼來配音「讀」的方法:

sub maybe ($$) { $_[1] ? $_[0] :() } 

my @list = (
    maybe("foo", $foo), 
    maybe("bar", $bar), 
); 

它有很多的這種指控x!!運營商的利益(雖然稍長),但有一個額外的獎金是您稍後再回來時可以真正理解您的代碼。

編輯:原型並沒有幫助Perl解析任何更好的東西,不讓我們排除括號,它只是防止Perl做我們不想要的東西。如果我們想挖溝,我們必須做一些工作。下面是沒有括號工作的另一個版本:

sub maybe { 
    my($var, $cond, @rest) = @_; 
    return @rest unless $cond; 
    return $var, @rest; 
} 

my @list = (
    maybe "foo", $foo, 
    maybe "bar", $bar, 
); 

無論我們做什麼用的原型,Perl將嘗試分析它作爲maybe("foo", $foo, maybe("bar", $bar)),所以如果我們想溝括號,我們只是不得不做出這樣的給正確的結果。

+0

+1另外,可能的參數的括號是可選的,因爲原型。 – 2010-02-19 13:25:04

+0

@eugene y - 這就是我使用原型的原因,但這是不正確的。沒有括號,它會嘗試解析爲'maybe(「foo」,$ foo,也許(「bar」,$ bar))''。原型拒絕了這一點,確保Perl不會嘗試做我們不希望它做的事情。當然,通過一些小小的工作,我們可以讓它在沒有括號的情況下工作。 – 2010-02-19 13:32:35

+0

感謝您糾正我。可以使用'maybe(「foo」,$ foo)'或'(也許是「foo」,$ foo)''。未原型版本似乎對我來說是一個矯枉過正的問題:) – 2010-02-19 14:13:45

1

我個人在這種情況下使用$foo ? 'foo' :(),因爲它是明確的(比較('foo') x!! $foo),並不需要特別的努力來理解(比較('foo') x !!$foo),並可以在列表上下文(比較push @list, 'foo' if $foo;)一起使用。

但是,當然,答案取決於您選擇什麼標準來選擇最佳選項。如果你通過混淆來比較它們,('foo') x!! $foo肯定會贏。如果你比較笨拙,push @list, 'foo' if $foo;將是第一個。或者你的意思是表現?我猜不是:-)

但是,如果你比較他們的風格,我的選擇是$foo ? 'foo' :()

2

雖然OP沒有要求它,這個問題給我提供了一個很好的藉口,use Benchmark;

下面的代碼:

use strict; 
use warnings; 
use Benchmark qw(cmpthese); 

my $foo = 1; 
my $bar = "true"; 

cmpthese(-10, { 
    "push" => sub { 
     my @list; 
     push @list, 'foo' if $foo; 
     push @list, 'bar' if $bar; 
    }, 
    "?::" => sub { 
     my @list = (
     $foo ? 'foo' :(), 
     $bar ? 'bar' :() 
    ); 
    }, 
    "x!!" => sub { 
     my @list = (
     ('foo') x!! $foo, 
     ('bar') x!! $bar 
    ); 
    } 
}); 

這裏有一些典型的結果:

  Rate x!! ?:: push 
x!! 646539/s -- -8% -12% 
?:: 701429/s 8% -- -5% 
push 736035/s 14% 5% -- 

鑑於布萊恩福伊的7% estimateBenchmark的不確定性,它絕對看起來像push是最快的增長方式。

總結:

$need4speed ? do { push @like $this} : try { something('less' x!! $obfuscated) }; 
# DISCLAIMER: This is not valid code 
相關問題