list 如何验证 Perl 中的数组(列表)中是否存在值?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/720482/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I verify that a value is present in an array (list) in Perl?
提问by MaxVT
I have a list of possible values:
我有一个可能值的列表:
@a = qw(foo bar baz);
How do I check in a concise way that a value $val
is present or absent in @a
?
如何以简洁的方式检查 中$val
存在或不存在值@a
?
An obvious implementation is to loop over the list, but I am sure TMTOWTDI.
一个明显的实现是遍历列表,但我确定TMTOWTDI。
Thanks to all who answered! The three answers I would like to highlight are:
感谢所有回答的人!我想强调的三个答案是:
The accepted answer - the most "built-in" and backward-compatible way.
RET's answeris the cleanest, but only good for Perl 5.10 and later.
draegtun's answeris (possibly) a bit faster, but requires using an additional module. I do not like adding dependencies if I can avoid them, and in this case do not need the performance difference, but if you have a 1,000,000-element list you might want to give this answer a try.
公认的答案 - 最“内置”和向后兼容的方式。
RET 的答案是最干净的,但仅适用于 Perl 5.10 及更高版本。
draegtun 的答案(可能)快一点,但需要使用额外的模块。如果我可以避免它们,我不喜欢添加依赖项,并且在这种情况下不需要性能差异,但是如果您有一个 1,000,000 个元素的列表,您可能想尝试一下这个答案。
采纳答案by Cheekysoft
Perl's bulit in grep() function is designed to do this.
Perl 在 grep() 函数中的构建就是为了做到这一点。
@matches = grep( /^MyItem$/, @someArray );
or you can insert any expression into the matcher
或者您可以在匹配器中插入任何表达式
@matches = grep( $_ == $val, @a );
回答by RET
If you have perl 5.10, use the smart-match operator~~
如果您有 perl 5.10,请使用智能匹配运算符~~
print "Exist\n" if $var ~~ @array;
print "Exist\n" if $var ~~ @array;
It's almost magic.
这几乎是魔术。
回答by brian d foy
This is answered in perlfaq4's answer to "How can I tell whether a certain element is contained in a list or array?".
这在perlfaq4对“如何判断某个元素是否包含在列表或数组中?”的回答中得到了回答。.
To search the perlfaq, you could search through the list of all questions in perlfaqusing your favorite browser.
要搜索perlfaq,你可以通过的所有问题列表中搜索perlfaq用你喜欢的浏览器。
From the command line, you can use the -q switch to perldoc to search for keywords. You would have found your answer by searching for "list":
从命令行,您可以使用 -q 开关到 perldoc 来搜索关键字。您可以通过搜索“列表”找到答案:
perldoc -q list
(portions of this answer contributed by Anno Siegel and brian d foy)
(此答案的部分内容由 Anno Siegel 和 brian d foy 提供)
Hearing the word "in" is an indication that you probably should have used a hash, not a list or array, to store your data. Hashes are designed to answer this question quickly and efficiently. Arrays aren't.
听到“in”一词表明您可能应该使用散列而不是列表或数组来存储数据。哈希旨在快速有效地回答这个问题。数组不是。
That being said, there are several ways to approach this. In Perl 5.10 and later, you can use the smart match operator to check that an item is contained in an array or a hash:
话虽如此,有几种方法可以解决这个问题。在 Perl 5.10 及更高版本中,您可以使用智能匹配运算符来检查项目是否包含在数组或散列中:
use 5.010;
if( $item ~~ @array )
{
say "The array contains $item"
}
if( $item ~~ %hash )
{
say "The hash contains $item"
}
With earlier versions of Perl, you have to do a bit more work. If you are going to make this query many times over arbitrary string values, the fastest way is probably to invert the original array and maintain a hash whose keys are the first array's values:
对于早期版本的 Perl,您必须做更多的工作。如果要对任意字符串值多次进行此查询,最快的方法可能是反转原始数组并维护一个哈希,其键是第一个数组的值:
@blues = qw/azure cerulean teal turquoise lapis-lazuli/;
%is_blue = ();
for (@blues) { $is_blue{$_} = 1 }
Now you can check whether $is_blue{$some_color}. It might have been a good idea to keep the blues all in a hash in the first place.
现在您可以检查是否 $is_blue{$some_color}。首先将蓝调保持在散列中可能是个好主意。
If the values are all small integers, you could use a simple indexed array. This kind of an array will take up less space:
如果值都是小整数,则可以使用简单的索引数组。这种数组将占用更少的空间:
@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;
Now you check whether $is_tiny_prime[$some_number].
现在检查是否 $is_tiny_prime[$some_number]。
If the values in question are integers instead of strings, you can save quite a lot of space by using bit strings instead:
如果有问题的值是整数而不是字符串,则可以通过使用位字符串来节省大量空间:
@articles = ( 1..10, 150..2000, 2017 );
undef $read;
for (@articles) { vec($read,$_,1) = 1 }
Now check whether vec($read,$n,1) is true for some $n.
现在检查 vec($read,$n,1) 对于某些 $n 是否为真。
These methods guarantee fast individual tests but require a re-organization of the original list or array. They only pay off if you have to test multiple values against the same array.
这些方法保证了快速的单独测试,但需要重新组织原始列表或数组。只有当您必须针对同一个数组测试多个值时,它们才会得到回报。
If you are testing only once, the standard module List::Util exports the function first for this purpose. It works by stopping once it finds the element. It's written in C for speed, and its Perl equivalent looks like this subroutine:
如果您只测试一次,则标准模块 List::Util 为此首先导出该函数。它的工作原理是在找到元素后停止。它是用 C 编写的以提高速度,它的 Perl 等效项如下所示:
sub first (&@) {
my $code = shift;
foreach (@_) {
return $_ if &{$code}();
}
undef;
}
If speed is of little concern, the common idiom uses grep in scalar context (which returns the number of items that passed its condition) to traverse the entire list. This does have the benefit of telling you how many matches it found, though.
如果速度无关紧要,常见的习惯用法是在标量上下文中使用 grep(它返回通过其条件的项目数)来遍历整个列表。不过,这确实有利于告诉您它找到了多少匹配项。
my $is_there = grep $_ eq $whatever, @array;
If you want to actually extract the matching elements, simply use grep in list context.
如果您想实际提取匹配的元素,只需在列表上下文中使用 grep 即可。
my @matches = grep $_ eq $whatever, @array;
回答by draegtun
Use the firstfunction from List::Utilwhich comes as standard with Perl....
使用List::Util 中的第一个函数,它是 Perl 的标准......
use List::Util qw/first/;
my @a = qw(foo bar baz);
if ( first { $_ eq 'bar' } @a ) { say "Found bar!" }
NB. firstreturns the first element it finds and so doesn't have to iterate through the complete list (which is what grepwill do).
注意。first返回它找到的第一个元素,因此不必遍历完整列表(这是grep将执行的操作)。
回答by neversaint
One possible approach is to use List::MoreUtils 'any' function.
一种可能的方法是使用 List::MoreUtils 'any' 函数。
use List::MoreUtils qw/any/;
my @array = qw(foo bar baz);
print "Exist\n" if any {($_ eq "foo")} @array;
Update: corrected based on zoul's comment.
更新:根据 zoul 的评论更正。
回答by zoul
Interesting solution, especially for repeated searching:
有趣的解决方案,特别是对于重复搜索:
my %hash;
map { $hash{$_}++ } @a;
print $hash{$val};
回答by mfontani
$ perl -e '@a = qw(foo bar baz);$val="bar";
if (grep{$_ eq $val} @a) {
print "found"
} else {
print "not found"
}'
found
成立
$val='baq';
not found
未找到
回答by Hynek -Pichi- Vychodil
If you don't like unnecessary dependency, implement any
or first
yourself
如果你不喜欢不必要的依赖,实现any
或者first
你自己
sub first (&@) {
my $code = shift;
$code->() and return $_ foreach @_;
undef
}
sub any (&@) {
my $code = shift;
$code->() and return 1 foreach @_;
undef
}