От ответа perlfaq4 на Как узнать, содержится ли определенный элемент в списке или массиве? :
(части этого ответа предоставлены Анно Сигелем и Брайаном Д. Фой)
Слушание слова «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;