如何在Perl中验证数组(列表)中是否存在值?

如何在Perl中验证数组(列表)中是否存在值?,perl,arrays,list,find,Perl,Arrays,List,Find,我有一个可能值的列表: @a = qw(foo bar baz); 如何简明地检查@a中是否存在值$val 一个明显的实现是循环列表,但我确信 感谢所有回答的人!我想强调的三个答案是: 公认的答案-最“内置”和向后兼容的方式 是最干净的,但只适用于Perl5.10及更高版本 可能会快一点,但需要使用额外的模块。如果可以避免,我不喜欢添加依赖项,在这种情况下,不需要性能差异,但是如果您有1000000个元素列表,您可能希望尝试一下这个答案 一种可能的方法是使用List::MoreUtils'a

我有一个可能值的列表:

@a = qw(foo bar baz);
如何简明地检查
@a
中是否存在值
$val

一个明显的实现是循环列表,但我确信


感谢所有回答的人!我想强调的三个答案是:

  • 公认的答案-最“内置”和向后兼容的方式

  • 是最干净的,但只适用于Perl5.10及更高版本

  • 可能会快一点,但需要使用额外的模块。如果可以避免,我不喜欢添加依赖项,在这种情况下,不需要性能差异,但是如果您有1000000个元素列表,您可能希望尝试一下这个答案


  • 一种可能的方法是使用List::MoreUtils'any'函数

    use List::MoreUtils qw/any/;
    
    my @array = qw(foo bar baz);
    
    print "Exist\n" if any {($_ eq "foo")} @array;
    

    更新:根据zoul的评论进行更正。

    有趣的解决方案,特别是对于重复搜索:

    my %hash;
    map { $hash{$_}++ } @a;
    print $hash{$val};
    
    Perl的bulit in grep()函数就是为此而设计的

    @matches = grep( /^MyItem$/, @someArray ); 
    
    也可以将任何表达式插入匹配器

    @matches = grep( $_ == $val, @a ); 
    

    如果您有perl 5.10,请使用~~

    如果$var~~@array,则打印“Exist\n”

    这几乎是魔术

    $ perl -e '@a = qw(foo bar baz);$val="bar";
    if (grep{$_ eq $val} @a) {
      print "found"
    } else {
      print "not found"
    }'
    
    发现

    找不到

    使用Perl标准的第一个函数

    use List::Util qw/first/;
    
    my @a = qw(foo bar baz);
    if ( first { $_ eq 'bar' } @a ) { say "Found bar!" }
    
    注意。first返回它找到的第一个元素,因此不必遍历完整的列表(grep将这样做)。

    这在的答案中得到了回答

    要搜索perlfaq,您可以使用您喜爱的浏览器在所有问题列表中进行搜索

    在命令行中,您可以使用-q开关到perldoc来搜索关键字。您可以通过搜索“列表”找到答案:


    (本答案的部分内容由Anno Siegel和brian d foy提供)

    听到“in”这个词表示您可能应该使用散列,而不是列表或数组来存储数据。散列是为了快速有效地回答这个问题而设计的。数组不是

    尽管如此,有几种方法可以实现这一点。在Perl 5.10及更高版本中,可以使用智能匹配运算符检查数组或哈希中是否包含项:

    use 5.010;
    
    if( $item ~~ @array )
        {
        say "The array contains $item"
        }
    
    if( $item ~~ %hash )
        {
        say "The hash contains $item"
        }
    
    对于早期版本的Perl,您需要做更多的工作。如果要对任意字符串值多次执行此查询,最快的方法可能是反转原始数组并维护其键为第一个数组值的哈希:

    @blues = qw/azure cerulean teal turquoise lapis-lazuli/;
    %is_blue = ();
    for (@blues) { $is_blue{$_} = 1 }
    
    现在您可以检查$is_blue{$some_color}。首先,把所有的布鲁斯音乐都放在一个杂烩里可能是个好主意

    如果值都是小整数,则可以使用简单的索引数组。这种阵列将占用更少的空间:

    @primes = (2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31);
    @is_tiny_prime = ();
    for (@primes) { $is_tiny_prime[$_] = 1 }
    # or simply  @istiny_prime[@primes] = (1) x @primes;
    
    现在,您检查$是否为_tiny _prime[$some _number]

    如果所讨论的值是整数而不是字符串,则使用位字符串可以节省大量空间:

    @articles = ( 1..10, 150..2000, 2017 );
    undef $read;
    for (@articles) { vec($read,$_,1) = 1 }
    
    现在检查vec($read,$n,1)对于某些$n是否为真

    这些方法保证了快速的单独测试,但需要重新组织原始列表或数组。只有当您必须针对同一数组测试多个值时,它们才有回报

    如果只测试一次,那么标准模块列表::Util将首先为此导出函数。一旦找到元素,它就会停止工作。它是用C编写的,表示速度,它的Perl等价物类似于以下子程序:

    sub first (&@) {
        my $code = shift;
        foreach (@_) {
            return $_ if &{$code}();
        }
        undef;
    }
    
    如果不太关心速度,那么常见的习惯用法是在标量上下文中使用grep(返回通过条件的项数)遍历整个列表。不过,这样做的好处是可以告诉您找到了多少匹配项

    my $is_there = grep $_ eq $whatever, @array;
    
    如果您想实际提取匹配元素,只需在列表上下文中使用grep即可

    my @matches = grep $_ eq $whatever, @array;
    

    如果您不喜欢不必要的依赖关系,请自己实现
    any
    首先

    sub first (&@) {
      my $code = shift;
      $code->() and return $_ foreach @_;
      undef
    }
    
    sub any (&@) {
      my $code = shift;
      $code->() and return 1 foreach @_;
      undef
    }
    

    定义(“foo”)总是正确的,你是说$eq‘foo’?我一直取下我给你的-1,它一直把它放回。。。希望这(第三次)不会发生!Zoul关于散列的建议非常接近最优,但是我建议,当您在程序过程中向数组添加和删除值时,在散列中添加和删除这些值。此外,尽管这很有效而且很常见,但一些人(我想包括我自己)会抱怨在无效上下文中使用map。为什么不改为@a的$hash{${}++?我不确定我是否看到List::Util的依赖性问题。它是Perl的标准配置,如果与qw/first/(如Draegtun所做的那样)一起使用,则只导入一个子例程。这本身不是问题,更多的是个人偏好。List::Util answer没有依赖性问题。如果是我,那将是公认的答案。我觉得不愿意使用核心模块是一种根深蒂固的迷信倾向。在这种情况下,grep{}几乎和first()一样好。按照愚人节的说法,如果使用导入的sub,我更喜欢List::MoreUtil::any(),因为概念(“如果List中的任何项满足条件,则返回真值”)在语义上比first()更符合问题(“返回第一个元素,其中BLOCK的结果是真值”)List::Util::first()具有作为核心模块(即无处不在)的优势。如果我正在寻找CPAN选项,那么我会认真考虑PARL6::结::任何…如果(any(@a)eq'baz'){}NB。从5.10.1开始,语义发生了一些变化,需要:
    if$var~~@array
    。为了帮助我把
    ~
    看作
    中的
    。谢谢-我们已经相应地交换了订单。我的perldoc url不再有效。这里有一个固定的:
    
    my @matches = grep $_ eq $whatever, @array;
    
    sub first (&@) {
      my $code = shift;
      $code->() and return $_ foreach @_;
      undef
    }
    
    sub any (&@) {
      my $code = shift;
      $code->() and return 1 foreach @_;
      undef
    }