如何在Perl中验证数组(列表)中是否存在值?
我有一个可能值的列表:如何在Perl中验证数组(列表)中是否存在值?,perl,arrays,list,find,Perl,Arrays,List,Find,我有一个可能值的列表: @a = qw(foo bar baz); 如何简明地检查@a中是否存在值$val 一个明显的实现是循环列表,但我确信 感谢所有回答的人!我想强调的三个答案是: 公认的答案-最“内置”和向后兼容的方式 是最干净的,但只适用于Perl5.10及更高版本 可能会快一点,但需要使用额外的模块。如果可以避免,我不喜欢添加依赖项,在这种情况下,不需要性能差异,但是如果您有1000000个元素列表,您可能希望尝试一下这个答案 一种可能的方法是使用List::MoreUtils'a
@a = qw(foo bar baz);
如何简明地检查@a
中是否存在值$val
一个明显的实现是循环列表,但我确信
感谢所有回答的人!我想强调的三个答案是:
一种可能的方法是使用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};
Perl的bulit in grep()函数就是为此而设计的
@matches = grep( /^MyItem$/, @someArray );
也可以将任何表达式插入匹配器
@matches = grep( $_ == $val, @a );
如果您有perl 5.10,请使用~~ 如果$var~~@array,则打印“Exist\n”代码> 这几乎是魔术
$ perl -e '@a = qw(foo bar baz);$val="bar";
if (grep{$_ eq $val} @a) {
print "found"
} else {
print "not found"
}'
发现
找不到使用Perl标准的第一个函数
use List::Util qw/first/;
my @a = qw(foo bar baz);
if ( first { $_ eq 'bar' } @a ) { say "Found bar!" }
注意。first返回它找到的第一个元素,因此不必遍历完整的列表(grep将这样做)。这在的答案中得到了回答
要搜索perlfaq,您可以使用您喜爱的浏览器在所有问题列表中进行搜索
在命令行中,您可以使用-q开关到perldoc来搜索关键字。您可以通过搜索“列表”找到答案:
(本答案的部分内容由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;
现在,您检查$是否为_tiny _prime[$some _number]
如果所讨论的值是整数而不是字符串,则使用位字符串可以节省大量空间:
@articles = ( 1..10, 150..2000, 2017 );
undef $read;
for (@articles) { vec($read,$_,1) = 1 }
现在检查vec($read,$n,1)对于某些$n是否为真
这些方法保证了快速的单独测试,但需要重新组织原始列表或数组。只有当您必须针对同一数组测试多个值时,它们才有回报
如果只测试一次,那么标准模块列表::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;
如果您不喜欢不必要的依赖关系,请自己实现
any
或首先
sub first (&@) {
my $code = shift;
$code->() and return $_ foreach @_;
undef
}
sub any (&@) {
my $code = shift;
$code->() and return 1 foreach @_;
undef
}
定义(“foo”)总是正确的,你是说$eq‘foo’?我一直取下我给你的-1,它一直把它放回。。。希望这(第三次)不会发生!Zoul关于散列的建议非常接近最优,但是我建议,当您在程序过程中向数组添加和删除值时,在散列中添加和删除这些值。此外,尽管这很有效而且很常见,但一些人(我想包括我自己)会抱怨在无效上下文中使用map。为什么不改为@a的$hash{${}++?我不确定我是否看到List::Util的依赖性问题。它是Perl的标准配置,如果与qw/first/(如Draegtun所做的那样)一起使用,则只导入一个子例程。这本身不是问题,更多的是个人偏好。List::Util answer没有依赖性问题。如果是我,那将是公认的答案。我觉得不愿意使用核心模块是一种根深蒂固的迷信倾向。在这种情况下,grep{}几乎和first()一样好。按照愚人节的说法,如果使用导入的sub,我更喜欢List::MoreUtil::any(),因为概念(“如果List中的任何项满足条件,则返回真值”)在语义上比first()更符合问题(“返回第一个元素,其中BLOCK的结果是真值”)List::Util::first()具有作为核心模块(即无处不在)的优势。如果我正在寻找CPAN选项,那么我会认真考虑PARL6::结::任何…如果(any(@a)eq'baz'){}NB。从5.10.1开始,语义发生了一些变化,需要:
if$var~~@array
。为了帮助我把~
看作中的。谢谢-我们已经相应地交换了订单。我的perldoc url不再有效。这里有一个固定的:
my @matches = grep $_ eq $whatever, @array;
sub first (&@) {
my $code = shift;
$code->() and return $_ foreach @_;
undef
}
sub any (&@) {
my $code = shift;
$code->() and return 1 foreach @_;
undef
}