由于 StackOverflow 上有很多类似的问题,不同的“正确答案”会返回不同的结果,因此我尝试对它们进行比较。这个问题似乎是分享我的小基准的好地方。
对于我的测试,我使用了一个包含 1000 个长度为 10 的元素(字符串)的测试集 (@test_set),其中只有一个元素 ($search_value) 与给定的字符串匹配。
我采用以下语句在 100,000 次循环中验证此元素的存在。
_grep
grep( $_ eq $search_value, @test_set )
_hash
{ map { $_ => 1 } @test_set }->{ $search_value }
_hash_premapped
$mapping->{ $search_value }
- 使用预先计算为
$mapping = { map { $_ => 1 } @test_set } 的$mapping(包含在最终测量中)
_正则表达式
sub{ my $rx = join "|", map quotemeta, @test_set; $search_value =~ /^(?:$rx)$/ }
_regex_prejoined
$search_value =~ /^(?:$rx)$/
- 使用正则表达式
$rx,该表达式预先计算为$rx = join "|", map quotemeta, @test_set;(包含在最终测量中)
_manual_first
sub{ foreach ( @test_set ) { return 1 if( $_ eq $search_value ); } return 0; }
_first
first { $_ eq $search_value } @test_set
_smart
$search_value ~~ @test_set
_any
any { $_ eq $search_value } @test_set
- 来自
List::MoreUtils(0.33 版)
在我的机器上(Ubuntu,3.2.0-60-generic,x86_64,Perl v5.14.2)我得到了以下结果。显示的值为秒,由Time::HiRes 的gettimeofday 和tv_interval(版本1.9726)返回。
元素$search_value位于数组@test_set中的位置0
_hash_premapped: 0.056211
_smart: 0.060267
_manual_first: 0.064195
_first: 0.258953
_any: 0.292959
_regex_prejoined: 0.350076
_grep: 5.748364
_regex: 29.27262
_hash: 45.638838
元素$search_value位于数组@test_set中的位置500
_hash_premapped: 0.056316
_regex_prejoined: 0.357595
_first: 2.337911
_smart: 2.80226
_manual_first: 3.34348
_any: 3.408409
_grep: 5.772233
_regex: 28.668455
_hash: 45.076083
元素$search_value位于数组@test_set中的第999位
_hash_premapped: 0.054434
_regex_prejoined: 0.362615
_first: 4.383842
_smart: 5.536873
_grep: 5.962746
_any: 6.31152
_manual_first: 6.59063
_regex: 28.695459
_hash: 45.804386
结论
检查数组中元素是否存在的最快方法是使用准备好的哈希。您当然可以按比例购买内存消耗,并且只有在您多次搜索集合中的元素时才有意义。如果您的任务包含少量数据并且只有一次或几次搜索,那么哈希甚至可能是最糟糕的解决方案。速度不一样,但类似的想法是使用准备好的正则表达式,这似乎有更短的准备时间。
在许多情况下,准备好的环境是没有选择的。
令人惊讶的是List::Util::first 的结果非常好,当涉及到没有准备好的环境的语句比较时。虽然在开始时具有搜索值(这也可能被解释为较小集合中的结果),但它非常接近收藏夹~~ 和any(甚至可能在测量不准确的范围内)。对于我较大的测试集中间或末尾的项目,first 绝对是最快的。