我试图找出一种方法来检查数组中值的存在,而不遍历数组。
我正在读取一个文件的参数。我有一长串不想处理的参数。我把这些不需要的参数放在一个数组@badparams中。
我想读取一个新的参数,如果它不存在于@badparams,处理它。如果@badparams中存在,请转到下一次读取。
我试图找出一种方法来检查数组中值的存在,而不遍历数组。
我正在读取一个文件的参数。我有一长串不想处理的参数。我把这些不需要的参数放在一个数组@badparams中。
我想读取一个新的参数,如果它不存在于@badparams,处理它。如果@badparams中存在,请转到下一次读取。
当前回答
简单地将数组转换为哈希:
my %params = map { $_ => 1 } @badparams;
if(exists($params{$someparam})) { ... }
你也可以添加更多(唯一的)参数到列表中:
$params{$newparam} = 1;
然后返回一个(唯一的)参数列表:
@badparams = keys %params;
其他回答
你可以在Perl 5.10中使用smartmatch特性,如下所示:
对于文字值查找,执行下面的操作即可。
if ( "value" ~~ @array )
对于标量查找,执行以下操作将与上述工作一样。
if ($val ~~ @array)
对于内联数组做下面,将工作如上。
if ( $var ~~ ['bar', 'value', 'foo'] )
在Perl 5.18中,smartmatch被标记为实验性的,因此你需要通过在你的脚本/模块中添加以下内容来打开实验性的pragma来关闭警告:
use experimental 'smartmatch';
或者,如果你想避免使用smartmatch,那么就像Aaron说的那样使用:
if ( grep( /^$value$/, @array ) ) {
#TODO:
}
这篇博文讨论了这个问题的最佳答案。
作为一个简短的总结,如果你可以安装CPAN模块,那么最有可读性的解决方案是:
any(@ingredients) eq 'flour';
or
@ingredients->contains('flour');
然而,更常见的习语是:
any { $_ eq 'flour' } @ingredients
但是请不要使用first()函数!它根本没有表达你代码的意图。不要使用~~“智能匹配”操作符:它已经坏了。不要使用grep()或带散列的解决方案:它们遍历整个列表。
Any()一旦找到你的值就会停止。
查看博客文章了解更多细节。
如果你需要知道数组中每个元素的数量,除了该元素的存在,你可以使用
my %bad_param_lookup;
@bad_param_lookup{ @bad_params } = ( 1 ) x @bad_params;
%bad_param_lookup = map { $_ => $bad_param_lookup{$_}++} @bad_params;
然后对于@bad_params中的每个$i, $bad_param_lookup{$i}包含@bad_params中的$i的数量
@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)
方法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;