Perl:测试值是否在数组中的好方法?

cod*_*fun 15 arrays perl

如果我有一个数组:

@int_array = (7,101,80,22,42);
Run Code Online (Sandbox Code Playgroud)

如何在不循环遍历每个元素的情况下检查整数值80是否在数组中?

yst*_*sth 31

你不能没有循环.这是数组意义的一部分.您可以使用grep或smartmatch使用隐式循环,但仍然存在循环.如果要避免循环,请改为使用哈希(或者另外).

# grep
if ( grep $_ == 80, @int_array ) ...

# smartmatch
use 5.010001;
if ( 80 ~~ @int_array ) ...
Run Code Online (Sandbox Code Playgroud)

在使用smartmatch之前,请注意:

http://search.cpan.org/dist/perl-5.18.0/pod/perldelta.pod#The_smartmatch_family_of_features_are_now_experimental:

smartmatch系列功能现在是实验性的

在v5.10.0中添加并在v5.10.1中进行了重大修订的智能匹配一直是一个常见的投诉点.尽管有许多方法可用,但它也证明了Perl的用户和实现者都存在问题和困惑.关于如何最好地解决问题,已经提出了许多建议.很明显,smartmatch几乎肯定会在将来改变或消失.不建议依赖其当前行为.

现在,当解析器看到〜,给定或何时发出警告.要禁用这些警告,可以将此行添加到适当的范围

  • `undef @hash {@array}`有效,但实际上没有记录.请改用@hash {@array} =()`. (2认同)
  • @DVK:这就是为什么我说"你不能".smartmatch或其他任何东西都是一个循环(可能通过每个元素)作为grep或for. (2认同)

DVK*_*DVK 7

CPAN解决方案:使用 List::MoreUtils

use List::MoreUtils qw{any}; 
print "found!\n" if any { $_ == 7 } (7,101,80,22,42);
Run Code Online (Sandbox Code Playgroud)

如果您需要在同一个数组中执行多次查找,则更有效的方法是将数组存储在哈希中一次并查找哈希值:

@int_array{@int_array} = 1;
foreach my $lookup_value (@lookup_values) {
    print "found $lookup_value\n" if exists $int_array{$lookup_value}
}
Run Code Online (Sandbox Code Playgroud)

为什么使用这个解决方案而不是替

  • 在5.10之前不能在Perl中使用智能匹配.根据该SO布赖恩·d FOY]交2,智能匹配是短路,所以它为5.10"任何"解决方案一样好.

  • grep即使1,000,000个长列表的第一个元素匹配,解决方案也会遍历整个列表.any将在发现第一场比赛时短路并退出,因此效率更高.原始海报明确表示"没有遍历每个元素"

  • 如果您需要进行大量查找,则哈希创建的一次性沉没成本使得哈希查找方法比任何其他方法都更有效.有关详细信息,请参阅此SO帖子

  • @kemp - IIRC,List :: MoreUtils有一个XS实现.这比前一次更快.如果使用本机Perl,那可能就是模块所做的事情. (2认同)