我有一个可能的值列表:
@a = qw(foo bar baz);
如何以简明的方式检查值$val
是否存在@a
?
一个明显的实现是遍历列表,但我确信TMTOWTDI.
感谢所有回答的人!我想强调的三个答案是:
接受的答案 - 最"内置"和向后兼容的方式.
RET的答案是最干净的,但只适用于Perl 5.10及更高版本.
draegtun的答案(可能)有点快,但需要使用额外的模块.我不喜欢添加依赖项,如果我可以避免它们,在这种情况下不需要性能差异,但如果你有一个1,000,000元素的列表,你可能想尝试这个答案.
RET.. 38
如果您有perl 5.10,请使用智能匹配运算符 ~~
print "Exist\n" if $var ~~ @array;
这几乎是魔术.
如果您有perl 5.10,请使用智能匹配运算符 ~~
print "Exist\n" if $var ~~ @array;
这几乎是魔术.
Perl在grep()函数中的优势就是为此而设计的.
@matches = grep( /^MyItem$/, @someArray );
或者您可以将任何表达式插入匹配器
@matches = grep( $_ == $val, @a );
这在perlfaq4的答案中得到了回答:"如何判断某个元素是否包含在列表或数组中?" .
要搜索perlfaq,您可以使用自己喜欢的浏览器在perlfaq中搜索所有问题的列表.
从命令行,您可以使用-q开关来perldoc搜索关键字.您可以通过搜索"列表"找到您的答案:
perldoc -q list
(这个答案的部分内容由Anno Siegel和brian d foy提供)
听到"in"这个词表示你可能应该使用散列而不是列表或数组来存储数据.哈希旨在快速有效地回答这个问题.数组不是.
话虽如此,有几种方法可以解决这个问题.在Perl 5.10及更高版本中,您可以使用智能匹配运算符来检查项目是否包含在数组或哈希中:
use 5.010; if( $item ~~ @array ) { say "The array contains $item" } if( $item ~~ %hash ) { say "The hash contains $item" }
使用早期版本的Perl,您需要做更多的工作.如果要在任意字符串值上多次进行此查询,最快的方法可能是反转原始数组并维护一个哈希,其键是第一个数组的值:
@blues = qw/azure cerulean teal turquoise lapis-lazuli/; %is_blue = (); for (@blues) { $is_blue{$_} = 1 }
现在你可以检查$ is_blue {$ some_color}.首先将蓝调全部放在哈希中可能是个好主意.
如果值都是小整数,则可以使用简单的索引数组.这种阵列占用的空间更少:
@primes = (2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31); @is_tiny_prime = (); for (@primes) { $is_tiny_prime[$_] = 1 } # or simply @istiny_prime[@primes] = (1) x @primes;
现在你检查$ is_tiny_prime [$ some_number].
如果有问题的值是整数而不是字符串,则可以使用位字符串来节省相当多的空间:
@articles = ( 1..10, 150..2000, 2017 ); undef $read; for (@articles) { vec($read,$_,1) = 1 }
现在检查一些$ n的vec($ read,$ n,1)是否为真.
这些方法保证了快速的单独测试,但需要重新组织原始列表或数组.如果必须针对同一阵列测试多个值,它们只会得到回报.
如果您只测试一次,标准模块List :: Util会首先导出该功能.它一旦找到元素就停止工作.它是用C语言编写的,它的Perl等价物就像这个子程序:
sub first (&@) { my $code = shift; foreach (@_) { return $_ if &{$code}(); } undef; }
如果速度很少受到关注,那么常见的习惯用法在标量上下文中使用grep(它返回通过其条件的项目数)来遍历整个列表.这确实有利于告诉你它找到了多少匹配.
my $is_there = grep $_ eq $whatever, @array;
如果要实际提取匹配元素,只需在列表上下文中使用grep.
my @matches = grep $_ eq $whatever, @array;
使用List :: Util中的第一个函数,它是Perl的标准配置....
use List::Util qw/first/; my @a = qw(foo bar baz); if ( first { $_ eq 'bar' } @a ) { say "Found bar!" }
NB.first返回它找到的第一个元素,因此不必遍历完整列表(这是grep将要执行的操作).
一种可能的方法是使用List :: MoreUtils'any'函数.
use List::MoreUtils qw/any/; my @array = qw(foo bar baz); print "Exist\n" if any {($_ eq "foo")} @array;
更新:根据zoul的评论更正.
有趣的解决方案,尤其是重复搜索:
my %hash; map { $hash{$_}++ } @a; print $hash{$val};