如何验证 Perl 中的数组(列表)中是不是存在值?

Posted

技术标签:

【中文标题】如何验证 Perl 中的数组(列表)中是不是存在值?【英文标题】:How can I verify that a value is present in an array (list) in Perl?如何验证 Perl 中的数组(列表)中是否存在值? 【发布时间】:2010-10-17 18:07:46 【问题描述】:

我有一个可能值的列表:

@a = qw(foo bar baz);

如何以简洁的方式检查 $val 值在 @a 中是否存在?

一个明显的实现是遍历列表,但我确信TMTOWTDI。


感谢所有回答的人!我想强调的三个答案是:

    公认的答案 - 最“内置”且向后兼容的方式。

    RET's answer 是最干净的,但只适用于 Perl 5.10 及更高版本。

    draegtun's answer(可能)快一点,但需要使用额外的模块。如果可以避免它们,我不喜欢添加依赖项,并且在这种情况下不需要性能差异,但是如果您有一个 1,000,000 个元素的列表,您可能想尝试一下这个答案。

【问题讨论】:

我不确定是否看到 List::Util 的依赖问题。它是 Perl 的标准,如果你将它与 qw/first/ 一起使用(就像 Draegtun 所做的那样),你只导入一个子例程。 这本身不是问题,更多的是个人喜好。 List::Util 答案没有依赖性问题。如果是我,那将是公认的答案。不愿意使用核心模块让我觉得这是一种根植于迷信的偏好。在这种情况下,grep 几乎一样好。 【参考方案1】:

如果你有 perl 5.10,请使用 smart-match operator ~~

print "Exist\n" if $var ~~ @array;

这几乎是魔法。

【讨论】:

注意。从 5.10.1 开始,语义发生了一些变化,它必须是:if $var ~~ @array。为了帮助我将~~ 视为in。参考:perldoc.perl.org/perldelta.html#Smart-match-changes 谢谢 - 已相应地交换了订单。 我的 perldoc url 不再有效。这是固定的:search.cpan.org/~dapm/perl-5.10.1/pod/…【参考方案2】:

Perl 的 grep() 函数中的 bulit 就是为此而设计的。

@matches = grep( /^MyItem$/, @someArray ); 

或者你可以在匹配器中插入任何表达式

@matches = grep( $_ == $val, @a ); 

【讨论】:

【参考方案3】:

perlfaq4 对"How can I tell whether a certain element is contained in a list or array?" 的回答中对此进行了回答。

要搜索 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 

现在检查 vec($read,$n,1) 对于某些 $n 是否为真。

这些方法保证了快速的单个测试,但需要重新组织原始列表或数组。只有当您必须针对同一个数组测试多个值时,它们才会得到回报。

如果您只测试一次,标准模块 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;

【讨论】:

【参考方案4】:

使用来自List::Util 的 first 函数,它是 Perl 的标准......

use List::Util qw/first/;

my @a = qw(foo bar baz);
if ( first  $_ eq 'bar'  @a )  say "Found bar!" 

注意。 first 返回它找到的第一个元素,因此不必遍历整个列表(这是 grep 将做的)。

【讨论】:

每个愚蠢的小子,如果使用导入的子,我更喜欢 List::MoreUtil::any() 因为这个概念(“如果 LIST 中的任何项目符合标准,则返回真值”)在语义上比 first() 更好地匹配问题(“返回 BLOCK 结果为真值的第一个元素。”) List::Util::first() 具有作为核心模块的优势(即无处不在)。如果我正在寻找 CPAN 选项,那么我会认真考虑 Perl6::Junction::any... if (any(@a) eq 'baz' ) 【参考方案5】:

一种可能的方法是使用 List::MoreUtils 'any' 函数。

use List::MoreUtils qw/any/;

my @array = qw(foo bar baz);

print "Exist\n" if any ($_ eq "foo") @array;

更新:根据zoul的评论更正。

【讨论】:

Defined("foo") 总是正确的,你的意思是 $_ eq 'foo'? 我一直在摘掉我给你的 -1 并且它一直把它重新戴上......希望它在这(第三)次保持关闭!【参考方案6】:

有趣的解决方案,尤其是重复搜索:

my %hash;
map  $hash$_++  @a;
print $hash$val;

【讨论】:

另外,虽然这很有效并且很常见,但有些人(我猜包括我自己)会抱怨在 void 上下文中使用 map。为什么不用 $hash$_++ 代替 @a?【参考方案7】:
$ perl -e '@a = qw(foo bar baz);$val="bar";
if (grep$_ eq $val @a) 
  print "found"
 else 
  print "not found"
'

找到

$val='baq';

找不到

【讨论】:

【参考方案8】:

如果您不喜欢不必要的依赖,请自行实现anyfirst

sub first (&@) 
  my $code = shift;
  $code->() and return $_ foreach @_;
  undef


sub any (&@) 
  my $code = shift;
  $code->() and return 1 foreach @_;
  undef

【讨论】:

以上是关于如何验证 Perl 中的数组(列表)中是不是存在值?的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 验证 - 如何检查给定数组中是不是存在值?

检查数据库 MySQL 中是不是存在值数组

在 Presto 中,如何检查我通过子查询获取的列表中是不是存在数组中的元素

使用 Perl 在列表列表中搜索项目

如何使用 Velocity 模板语言检查数组中是不是存在值

如何检查一个值是不是存在于Ruby中的数组中