我试图找出一种方法来检查数组中值的存在,而不遍历数组。

我正在读取一个文件的参数。我有一长串不想处理的参数。我把这些不需要的参数放在一个数组@badparams中。

我想读取一个新的参数,如果它不存在于@badparams,处理它。如果@badparams中存在,请转到下一次读取。


当前回答

方法1:grep(可能小心,而值是一个正则表达式)。

如果查看资源,尽量避免使用grep。

if ( grep( /^$value$/, @badparams ) ) {
  print "found";
}

方法二:线性搜索

for (@badparams) {
    if ($_ eq $value) {
       print "found";
       last;
    }
}

方法3:使用散列

my %hash = map {$_ => 1} @badparams;
print "found" if (exists $hash{$value});

方法四:smartmatch

(在Perl 5.10中添加,在Perl 5.18中标记为实验性)。

use experimental 'smartmatch';  # for perl 5.18
print "found" if ($value ~~ @badparams);

方法5:使用List::MoreUtils模块

use List::MoreUtils qw(any);
@badparams = (1,2,3);
$value = 1;
print "found" if any {$_ == $value} @badparams;

其他回答

简单地将数组转换为哈希:

my %params = map { $_ => 1 } @badparams;

if(exists($params{$someparam})) { ... }

你也可以添加更多(唯一的)参数到列表中:

$params{$newparam} = 1;

然后返回一个(唯一的)参数列表:

@badparams = keys %params;

这里肯定需要一个哈希。将坏的参数作为键放在散列中,然后决定某个特定参数是否存在于散列中。

our %bad_params = map { $_ => 1 } qw(badparam1 badparam2 badparam3)

if ($bad_params{$new_param}) {
  print "That is a bad parameter\n";
}

如果您真的对数组感兴趣,请查看List::Util或List::MoreUtils

@eakssjo的基准测试被打破了——测量在循环中创建哈希和在循环中创建正则表达式。修正版本(加上我已经添加了List::Util::first和List::MoreUtils::any):

use List::Util qw(first);
use List::MoreUtils qw(any);
use Benchmark;

my @list = ( 1..10_000 );
my $hit = 5_000;
my $hit_regex = qr/^$hit$/; # precompute regex
my %params;
$params{$_} = 1 for @list;  # precompute hash
timethese(
    100_000, {
        'any' => sub {
            die unless ( any { $hit_regex } @list );
        },
        'first' => sub {
            die unless ( first { $hit_regex } @list );
        },
        'grep' => sub {
            die unless ( grep { $hit_regex } @list );
        },
        'hash' => sub {
            die unless ( $params{$hit} );
        },
    });

结果(100_000次迭代,比@eakssjo的答案多十倍):

Benchmark: timing 100000 iterations of any, first, grep, hash...
       any:  0 wallclock secs ( 0.67 usr +  0.00 sys =  0.67 CPU) @ 149253.73/s (n=100000)
     first:  1 wallclock secs ( 0.63 usr +  0.01 sys =  0.64 CPU) @ 156250.00/s (n=100000)
      grep: 42 wallclock secs (41.95 usr +  0.08 sys = 42.03 CPU) @ 2379.25/s (n=100000)
      hash:  0 wallclock secs ( 0.01 usr +  0.00 sys =  0.01 CPU) @ 10000000.00/s (n=100000)
            (warning: too few iterations for a reliable count)

有两种方法。您可以使用将值扔到查找表的散列中,正如其他文章所建议的那样。(我再加一个成语。)

my %bad_param_lookup;
@bad_param_lookup{ @bad_params } = ( 1 ) x @bad_params;

但如果它的数据主要是单词字符,没有太多元,你可以把它转储到一个正则表达式的交替:

use English qw<$LIST_SEPARATOR>;

my $regex_str = do { 
    local $LIST_SEPARATOR = '|';
    "(?:@bad_params)";
 };

 # $front_delim and $back_delim being any characters that come before and after. 
 my $regex = qr/$front_delim$regex_str$back_delim/;

这个解决方案必须针对您正在寻找的“坏值”类型进行调优。这对于某些类型的字符串来说可能是完全不合适的,买者自负。

@files是一个已存在的数组

my @new_values =  grep(/^2[\d].[\d][A-za-z]?/,@files);

print join("\n", @new_values);

print "\n";

/ ^ 2 \ [d]。[\ d] [A-za-z]吗?/ =从2开始的值这里可以放入任何正则表达式