Mel*_*Mel 226 arrays perl comparison
我试图找出一种方法来检查数组中是否存在值而不迭代数组.
我正在读取参数的文件.我有一长串我不想处理的参数.我把这些不需要的参数放在一个数组中@badparams.
我想读一个新参数,如果它不存在@badparams,请处理它.如果确实存在@badparams,请转到下一个读取.
Aar*_*ris 211
最佳通用 - 特别是短阵列(1000个或更少项目)和编码器,不确定哪种优化最适合他们的需求.
# $value can be any regex. be safe
if ( grep( /^$value$/, @array ) ) {
print "found it";
}
Run Code Online (Sandbox Code Playgroud)
已经提到,即使数组中的第一个值匹配,grep也会遍历所有值.这是事实,但对于大多数情况来说,grep仍然非常快.如果你在谈论短阵列(少于1000个项目),那么大多数算法都会非常快.如果您正在讨论非常长的数组(1,000,000个项目),那么无论该项目是数组中的第一个,中间还是最后一个,grep都是可以接受的.
更长阵列的优化案例:
如果您的数组已排序,请使用"二进制搜索".
如果多次重复搜索相同的数组,请先将其复制到哈希中,然后检查哈希值.如果内存是一个问题,那么将每个项目从数组移动到哈希.内存效率更高但会破坏原始阵列.
如果在数组中重复搜索相同的值,则懒惰地构建缓存.(当搜索每个项目时,首先检查搜索结果是否存储在持久化哈希中.如果在哈希中找不到搜索结果,则搜索数组并将结果放入持久化哈希中,以便下次我们将在哈希中找到它并跳过搜索).
注意:处理长数组时,这些优化只会更快.不要过度优化.
jkr*_*mer 182
只需将数组转换为哈希:
my %params = map { $_ => 1 } @badparams;
if(exists($params{$someparam})) { ... }
Run Code Online (Sandbox Code Playgroud)
您还可以在列表中添加更多(唯一)参数:
$params{$newparam} = 1;
Run Code Online (Sandbox Code Playgroud)
然后得到一个(唯一的)参数列表:
@badparams = keys %params;
Run Code Online (Sandbox Code Playgroud)
Bit*_*map 117
您可以在Perl 5.10中使用smartmatch功能,如下所示:
对于字面值查找,下面的操作就可以了.
if ( "value" ~~ @array )
Run Code Online (Sandbox Code Playgroud)
对于标量查找,执行以下操作将如上所述.
if ($val ~~ @array)
Run Code Online (Sandbox Code Playgroud)
对于下面的内联数组,将按上述方式工作.
if ( $var ~~ ['bar', 'value', 'foo'] )
Run Code Online (Sandbox Code Playgroud)
在Perl 5.18中, smartmatch被标记为实验性的,因此您需要通过在下面添加脚本/模块来打开实验性编译指示来关闭警告:
use experimental 'smartmatch';
Run Code Online (Sandbox Code Playgroud)
或者,如果你想避免使用smartmatch - 那么就像Aaron所说:
if ( grep( /^$value$/, @array ) ) {
#TODO:
}
Run Code Online (Sandbox Code Playgroud)
mas*_*cip 43
这篇博客文章讨论了这个问题的最佳答案.
作为简短摘要,如果您可以安装CPAN模块,那么最易读的解决方案是:
any(@ingredients) eq 'flour';
Run Code Online (Sandbox Code Playgroud)
要么
@ingredients->contains('flour');
Run Code Online (Sandbox Code Playgroud)
然而,更常见的习语是:
any { $_ eq 'flour' } @ingredients
Run Code Online (Sandbox Code Playgroud)
但请不要使用该first()功能!它根本不表达您的代码的意图.不要使用~~"智能匹配"操作符:它已损坏.并且不要使用grep()带有哈希的解决方案:它们遍历整个列表.
any() 一旦找到你的价值就会停止.
查看博客文章了解更多详情.
aks*_*sel 11
尽管使用起来很方便,但转换为哈希的解决方案似乎需要相当多的性能,这对我来说是一个问题.
#!/usr/bin/perl
use Benchmark;
my @list;
for (1..10_000) {
push @list, $_;
}
timethese(10000, {
'grep' => sub {
if ( grep(/^5000$/o, @list) ) {
# code
}
},
'hash' => sub {
my %params = map { $_ => 1 } @list;
if ( exists($params{5000}) ) {
# code
}
},
});
Run Code Online (Sandbox Code Playgroud)
基准测试输出:
Benchmark: timing 10000 iterations of grep, hash...
grep: 8 wallclock secs ( 7.95 usr + 0.00 sys = 7.95 CPU) @ 1257.86/s (n=10000)
hash: 50 wallclock secs (49.68 usr + 0.01 sys = 49.69 CPU) @ 201.25/s (n=10000)
Run Code Online (Sandbox Code Playgroud)
Xae*_*ess 11
@ 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} );
},
});
Run Code Online (Sandbox Code Playgroud)
结果(这是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)
Run Code Online (Sandbox Code Playgroud)
grep如果查看资源,尽量避免使用.
if ( grep( /^$value$/, @badparams ) ) {
print "found";
}
Run Code Online (Sandbox Code Playgroud)
for (@badparams) {
if ($_ eq $value) {
print "found";
}
}
Run Code Online (Sandbox Code Playgroud)
my %hash = map {$_ => 1} @badparams;
print "found" if (exists $hash{$value});
Run Code Online (Sandbox Code Playgroud)
(在Perl 5.10中添加,在Perl 5.18中标记为实验).
use experimental 'smartmatch'; # for perl 5.18
print "found" if ($value ~~ @badparams);
Run Code Online (Sandbox Code Playgroud)
List::MoreUtilsuse List::MoreUtils qw(any uniq);;
@badparams = (1,2,3);
$value = 1;
print "found" if any {$_ eq $value} @badparams;
Run Code Online (Sandbox Code Playgroud)