繁体   English   中英

有条件地将元素包括在列表中的最佳方法是什么?

[英]What's the best way to conditionally include an element in a list?

可能的方式:

  1. 使用push

     my @list; push @list, 'foo' if $foo; push @list, 'bar' if $bar; 
  2. 使用条件运算符

     my @list = ( $foo ? 'foo' : (), $bar ? 'bar' : (), ); 
  3. 使用x!! 布尔列表壁球运算符

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

哪一个更好,为什么?

好吧,他们都做不同的事情。

但是,在所有其他因素都相同的情况下,

push @list, 'foo' if $foo;

是最直接传达其含义的语句,因此应首选。

如果您不得不停下来想一想应该执行与推送数组元素一样简单的语句,那么您在做错了什么。

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

如果这是在其他地方进行的一些巨大初始化的一部分,则可以确定。

我认为使用

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

表示程序员拥有- 我该如何放置? - 问题

顺便说一句,没有所谓的x!! 复合运算符。 !! 双重逻辑否定 它将任意的false值转换为已定义但为false的值(空字符串),该值在perl需要数字的地方使用时将产生0 真值将转换为1 在这里!! $foo$bar并将其编写为x!! $foo x!! $foo不必要地混淆了代码的含义。

x重复运算符 所以,

 ('foo') x !!$foo;

表示一次重复('foo')一次,这取决于$foo是true还是false

PS:当然,结果是有一篇PerlMonks文章介绍了所谓的布尔列表壁球运算符 我阅读了这篇文章 ,发现它没有说服力。

我想建议我对“可读”方法进行配音:

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

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

它有许多所谓的x!!的好处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)) ,因此,如果我们想抛开括号,我们只需要使它成为括号即可。给出正确的结果。

尽管OP并没有要求这样做,但是这个问题为我提供了use Benchmark;的很好的借口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%   --

鉴于brian d foy对Benchmark的不确定性的估计7% ,显然push似乎是最快的增长方式。

加起来:

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

我个人使用$foo ? 'foo' : () $foo ? 'foo' : ()在这种情况下,因为很明显(与('foo') x!! $foo ),不需要特别的努力就可以理解(与('foo') x !!$foo比较('foo') x !!$foo ),并且可以在列表上下文中使用(与push @list, 'foo' if $foo; )。

但是,当然,答案取决于您选择哪种标准来选择最佳选项。 如果通过混淆比较它们,则('foo') x!! $foo ('foo') x!! $foo一定会赢。 如果比较笨拙, push @list, 'foo' if $foo; 将是第一个。 还是您的意思是性能? 我猜不会 :-)

但是,如果按风格比较它们,我的选择是$foo ? 'foo' : () $foo ? 'foo' : ()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM