我试图找出一种方法来检查数组中值的存在,而不遍历数组。
我正在读取一个文件的参数。我有一长串不想处理的参数。我把这些不需要的参数放在一个数组@badparams中。
我想读取一个新的参数,如果它不存在于@badparams,处理它。如果@badparams中存在,请转到下一次读取。
我试图找出一种方法来检查数组中值的存在,而不遍历数组。
我正在读取一个文件的参数。我有一长串不想处理的参数。我把这些不需要的参数放在一个数组@badparams中。
我想读取一个新的参数,如果它不存在于@badparams,处理它。如果@badparams中存在,请转到下一次读取。
当前回答
最佳通用-特别是短数组(1000项或更少)和不确定哪种优化最适合他们的需求的编码员。
# $value can be any regex. be safe
if ( grep( /^$value$/, @array ) ) {
print "found it";
}
前面提到过,即使数组中的第一个值匹配,grep也会遍历所有值。这是事实,但是grep在大多数情况下仍然非常快。如果你谈论的是短数组(少于1000项),那么大多数算法无论如何都会非常快。如果您谈论的是非常长的数组(1,000,000个项),无论项是数组中的第一个、中间还是最后一个,grep都是可以接受的。
更长的数组优化案例:
如果你的数组是排序的,使用“二分搜索”。
如果重复搜索同一数组多次,则先将其复制到哈希中,然后再检查哈希。如果内存是一个问题,那么将每个项从数组移动到散列中。内存效率更高,但会破坏原始数组。
如果在数组中重复搜索相同的值,则惰性地构建缓存。(在搜索每个项时,首先检查搜索结果是否存储在持久散列中。如果在哈希中没有找到搜索结果,则搜索数组并将结果放入持久哈希中,以便下次在哈希中找到它并跳过搜索)。
注意:这些优化只会在处理长数组时更快。不要过度优化。
其他回答
有两种方法。您可以使用将值扔到查找表的散列中,正如其他文章所建议的那样。(我再加一个成语。)
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/;
这个解决方案必须针对您正在寻找的“坏值”类型进行调优。这对于某些类型的字符串来说可能是完全不合适的,买者自负。
如果你需要知道数组中每个元素的数量,除了该元素的存在,你可以使用
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的数量
这里肯定需要一个哈希。将坏的参数作为键放在散列中,然后决定某个特定参数是否存在于散列中。
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
简单地将数组转换为哈希:
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:
}