【问题标题】:How can I verify that a value is present in an array (list) in Perl?如何验证 Perl 中的数组(列表)中是否存在值?
【发布时间】:2010-10-17 18:07:46
【问题描述】:

我有一个可能值的列表:

@a = qw(foo bar baz);

如何以简洁的方式检查 $val 值在 @a 中是否存在?

一个明显的实现是遍历列表,但我确信TMTOWTDI


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

  1. 公认的答案 - 最“内置”且向后兼容的方式。

  2. RET's answer 是最干净的,但只适用于 Perl 5.10 及更高版本。

  3. draegtun's answer(可能)快一点,但需要使用额外的模块。如果可以避免它们,我不喜欢添加依赖项,并且在这种情况下不需要性能差异,但是如果您有一个 1,000,000 个元素的列表,您可能想尝试一下这个答案。

【问题讨论】:

  • 我不确定是否看到 List::Util 的依赖问题。它是 Perl 的标准,如果你将它与 qw/first/ 一起使用(就像 Draegtun 所做的那样),你只导入一个子例程。
  • 这本身不是问题,更多的是个人喜好。
  • List::Util 答案没有依赖性问题。如果是我,那将是公认的答案。不愿意使用核心模块让我觉得这是一种根植于迷信的偏好。在这种情况下,grep {} 几乎一样好。

标签: perl arrays list find


【解决方案1】:

如果你有 perl 5.10,请使用 smart-match operator ~~

print "Exist\n" if $var ~~ @array;

这几乎是魔法。

【讨论】:

【解决方案2】:

Perl 的 grep() 函数中的 bulit 就是为此而设计的。

@matches = grep( /^MyItem$/, @someArray ); 

或者你可以在匹配器中插入任何表达式

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

【讨论】:

    【解决方案3】:

    perlfaq4"How can I tell whether a certain element is contained in a list or array?" 的回答中对此进行了回答。

    要搜索 perlfaq,您可以使用您喜欢的浏览器搜索 perlfaq 中的所有问题列表。

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

    perldoc -q list
    

    (部分答案由 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;
    

    现在你检查 $is_tiny_prime[$some_number] 是否。

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

    @articles = ( 1..10, 150..2000, 2017 );
    undef $read;
    for (@articles) { vec($read,$_,1) = 1 }
    

    现在检查 vec($read,$n,1) 对于某些 $n 是否为真。

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

    如果您只测试一次,标准模块 List::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;
    

    【讨论】:

      【解决方案4】:

      使用来自List::Utilfirst 函数,它是 Perl 的标准......

      use List::Util qw/first/;
      
      my @a = qw(foo bar baz);
      if ( first { $_ eq 'bar' } @a ) { say "Found bar!" }
      

      注意。 first 返回它找到的第一个元素,因此不必遍历整个列表(这是 grep 将做的)。

      【讨论】:

      • 每个愚蠢的小子,如果使用导入的子,我更喜欢 List::MoreUtil::any() 因为这个概念(“如果 LIST 中的任何项目符合标准,则返回真值”)在语义上比 first() 更好地匹配问题(“返回 BLOCK 结果为真值的第一个元素。”)
      • List::Util::first() 具有作为核心模块的优势(即无处不在)。如果我正在寻找 CPAN 选项,那么我会认真考虑 Perl6::Junction::any... if (any(@a) eq 'baz' ) {}
      【解决方案5】:

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

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

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

      【讨论】:

      • Defined("foo") 总是正确的,你的意思是 $_ eq 'foo'?
      • 我一直在摘掉我给你的 -1 并且它一直把它重新戴上......希望它在这(第三)次保持关闭!
      【解决方案6】:

      有趣的解决方案,尤其是重复搜索:

      my %hash;
      map { $hash{$_}++ } @a;
      print $hash{$val};
      

      【讨论】:

      • 另外,虽然这很有效并且很常见,但有些人(我猜包括我自己)会抱怨在 void 上下文中使用 map。为什么不用 $hash{$_}++ 代替 @a?
      【解决方案7】:
      $ perl -e '@a = qw(foo bar baz);$val="bar";
      if (grep{$_ eq $val} @a) {
        print "found"
      } else {
        print "not found"
      }'
      

      找到

      $val='baq';
      

      找不到

      【讨论】:

        【解决方案8】:

        如果您不喜欢不必要的依赖,请自行实现anyfirst

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

        【讨论】:

          猜你喜欢
          • 2015-11-29
          • 2021-02-14
          • 2019-03-11
          • 1970-01-01
          • 2013-08-25
          • 1970-01-01
          • 2016-07-24
          • 2014-12-11
          • 1970-01-01
          相关资源
          最近更新 更多