Perl:if(列表中的元素)

Jon*_*han 69 arrays perl

我正在寻找列表中元素的存在.

在Python中有一个in关键字,我会做类似的事情:

if element in list:
    doTask
Run Code Online (Sandbox Code Playgroud)

在Perl中是否有类似的东西而不必手动遍历整个列表?

Bra*_*ert 110

更新:

smartmatch系列功能现在是实验性的

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

现在,当解析器看到〜,给定或何时发出警告.




如果你可以逃避需要Perl v5.10,那么你可以使用以下任何一个例子.

Perl 5.12中出现的一件事是使用后修复版本的能力when.这使它更像是ifunless.

given( $element ){
  ... when @list;
}
Run Code Online (Sandbox Code Playgroud)

如果您必须能够在旧版本的Perl上运行,那么仍有几个选项.

  • 你可能认为你可以使用List :: Util :: first,但是有一些边缘条件使它成为问题.

    在这个例子中,很明显我们想成功匹配0.不幸的是,这段代码failure每次都会打印.

    use List::Util qw'first';
    my $element = 0;
    if( first { $element eq $_ } 0..9 ){
      print "success\n";
    } else {
      print "failure\n";
    }
    
    Run Code Online (Sandbox Code Playgroud)

    您可以检查已first定义的返回值,但如果我们确实希望匹配undef成功,则会失败.

  • grep但是你可以放心使用.

    if( grep { $element eq $_ } 0..9 ){ ... }
    
    Run Code Online (Sandbox Code Playgroud)

    这是安全的,因为grep在标量上下文中调用.在标量上下文中调用时,数组返回元素数.所以即使我们试图匹配,这将继续有效undef.

  • 你可以使用一个封闭的for循环.只要确保你打电话last,在成功的比赛中退出循环.否则,您可能会多次运行代码.

    for( @array ){
      if( $element eq $_ ){
        ...
        last;
      }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 你可以将for循环放在if语句的条件中......

    if(
      do{
        my $match = 0;
        for( @list ){
          if( $element eq $_ ){
            $match = 1;
            last;
          }
        }
        $match; # the return value of the do block
      }
    ){
      ...
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • ...但是forif声明之前放置循环可能更清楚.

    my $match = 0;
    for( @list ){
      if( $_ eq $element ){
        $match = 1;
        last;
      }
    }
    
    if( $match ){ ... }
    
    Run Code Online (Sandbox Code Playgroud)
  • 如果您只是匹配字符串,您也可以使用哈希.如果你的程序@list很大,这可以加速你的程序,并且你将要%hash多次匹配.特别是如果@array不改变,因为那时你只需要加载%hash一次.

    my %hash = map { $_, 1 } @array;
    if( $hash{ $element } ){ ... }
    
    Run Code Online (Sandbox Code Playgroud)
  • 您也可以制作自己的子程序.这是使用原型有用的情况之一.

    sub in(&@){
      local $_;
      my $code = shift;
      for( @_ ){ # sets $_
        if( $code->() ){
          return 1;
        }
      }
      return 0;
    }
    
    if( in { $element eq $_ } @list ){ ... }
    
    Run Code Online (Sandbox Code Playgroud)

  • 请注意,"给定","何时"和"智能匹配运算符"现在[从perl 5.18开始标记为"实验"](http://search.cpan.org/dist/perl-5.18.0/pod/ perldelta.pod#The_smartmatch_family_of_features_are_now_experimental)并将生成警告.答案的[智能匹配~~](http://perldoc.perl.org/perlsyn.html#Smart-matching-in-detail)链接也不再有任何`#Smart-matching-in-detail`片段. (5认同)
  • @xxxxxxx你这么说,但我最高的投票答案通常也是最长的. (3认同)

jro*_*way 15

if( $element ~~ @list ){
   do_task
}
Run Code Online (Sandbox Code Playgroud)

~~ 是"智能匹配运算符",并且不仅仅列出成员资格检测.

  • 请注意,"智能匹配运算符"现在[从perl 5.18开始标记为"实验性"](http://search.cpan.org/dist/perl-5.18.0/pod/perldelta.pod#The_smartmatch_family_of_features_are_now_experimental)并将生成警告.答案的[智能匹配~~](http://perldoc.perl.org/perlsyn.html#Smart-matching-in-detail)链接也不再有任何`#Smart-matching-in-detail`片段. (2认同)

DVK*_*DVK 9

列表::的Util ::第一

$foo = first { ($_ && $_ eq "value" } @list;    # first defined value in @list
Run Code Online (Sandbox Code Playgroud)

或者用于手动滚动类型:

my $is_in_list = 0;
foreach my $elem (@list) {
    if ($elem && $elem eq $value_to_find) {
        $is_in_list = 1;
        last;
    }
}
if ($is_in_list) {
   ...
Run Code Online (Sandbox Code Playgroud)

一个略有不同的版本可能会在很长的列表上更快一些:

my $is_in_list = 0;
for (my $i = 0; i < scalar(@list); ++$i) {
    if ($list[i] && $list[i] eq $value_to_find) {
        $is_in_list = 1;
        last;
    }
}
if ($is_in_list) {
   ...
Run Code Online (Sandbox Code Playgroud)


Sin*_*nür 8

如果您计划多次执行此操作,则可以在空间中进行权衡以查找查找时间:

#!/usr/bin/perl

use strict; use warnings;

my @array = qw( one ten twenty one );
my %lookup = map { $_ => undef } @array;

for my $element ( qw( one two three ) ) {
    if ( exists $lookup{ $element }) {
        print "$element\n";
    }
}
Run Code Online (Sandbox Code Playgroud)

假设元素出现的次数@array不重要且内容@array是简单的标量.


ema*_*zep 7

列表:: MoreUtils

在perl> = 5.10时,智能匹配运算符肯定是最简单的方法,正如许多其他人已经说过的那样.

在旧版本的perl上,我建议使用List :: MoreUtils :: any.

List::MoreUtils 不是一个核心模块(有人说它应该是),但它非常受欢迎,它包含在主要的perl发行版中.

它具有以下优点:

  • 它返回true/false(如Python的in那样)而不是元素的值,List::Util::first如上所述(这使得很难测试);
  • 不像grep,它停在第一个通过测试的元素上(perl的智能匹配操作符也是短路的);
  • 它适用于任何perl版本(嗯,至少> = 5.00503).

以下示例适用于任何搜索(标量)值,包括undef:

use List::MoreUtils qw(any);

my $value = 'test'; # or any other scalar
my @array = (1, 2, undef, 'test', 5, 6);

no warnings 'uninitialized';

if ( any { $_ eq $value } @array ) {
    print "$value present\n"
}
Run Code Online (Sandbox Code Playgroud)

PS

(在生产代码中,最好缩小范围no warnings 'uninitialized').


Hyn*_*dil 6

TIMTOWTDI

sub is (&@) {
  my $test = shift;
  $test->() and return 1 for @_;
  0
}

sub in (@) {@_}

if( is {$_ eq "a"} in qw(d c b a) ) {
  print "Welcome in perl!\n";
}
Run Code Online (Sandbox Code Playgroud)


mob*_*mob 5

grep 在这里很有帮助

if (grep { $_ eq $element } @list) {
    ....
}
Run Code Online (Sandbox Code Playgroud)

  • `List :: Util :: first`可能是一种稍微有效的方法. (6认同)
  • 我用一个大的列表测试了这个,两者都非常快.当速度差异明显时,我的机器已经烧毁了6演出的RAM.如果你的名单是qw(foo bar baz),它可能并不重要. (4认同)