2010-12-31 4 views
11

Если у меня есть массив:Perl: Хороший способ проверить, есть ли значение в массиве?

@int_array = (7,101,80,22,42); 

Как я могу проверить, если целое значение 80 в массиве без зацикливания через каждый элемент?

+0

Выглядит как дубликат: http://stackoverflow.com/questions/2860226 – Calimo

+0

Возможный дубликат [Как проверить, содержит ли массив Perl определенное значение?] (Http://stackoverflow.com/questions/2860226/how-can-i-check-if-a-perl-array-contains-a-specific-value) – ThisSuitIsBlackNot

ответ

29

Вы не можете без зацикливания. Это часть того, что означает быть массивом. Вы можете использовать неявный цикл, используя grep или smartmatch, но есть еще цикл. Если вы хотите избежать цикла, используйте вместо него хеш (или дополнительно).

# grep 
if (grep $_ == 80, @int_array) ... 

# smartmatch 
use 5.010001; 
if (80 ~~ @int_array) ... 

Перед использованием smartmatch, обратите внимание:

http://search.cpan.org/dist/perl-5.18.0/pod/perldelta.pod#The_smartmatch_family_of_features_are_now_experimental:

smartmatch семейство функций теперь экспериментальной

Смарт матч, добавил в v5.10.0 и существенно переработан в п.5.10.1, является регулярной жалобой. Хотя есть несколько способов, в которых это полезно, он также оказался проблематичным и запутанным как для пользователей, так и для разработчиков Perl. Был предложен ряд предложений о том, как наилучшим образом решить эту проблему. Понятно, что smartmatch почти наверняка либо изменится, либо уйдет в будущем. Опираясь на его текущее поведение не рекомендуется.

Предупреждения будут выдаваться, когда парсер увидит ~~, данный или когда. Чтобы отключить эти предупреждения, вы можете добавить эту строку в соответствующую область

+0

++. Умный матч (или, может быть, что-то из List :: MoreUtils) - это путь. Для полноты, вот как вы могли сделать это с хешем: my @array = 1..1000; my% hash; undef @hash {@array}; скажем, «10 в массиве!» если существует $ hash {10}; – Hugmeir

+2

'undef @hash {@array}' работает, но на самом деле не документирован. вместо этого используйте '@hash {@array} =()'. – ysth

+0

Я не был уверен, что вы имели в виду, поэтому я нашел googled и нашел это: http://www.perlmonks.org/?node_id=435223 Спасибо за исправление, ysth! – Hugmeir

0
if (grep /^80$/, @int_array) { 
    ... 
} 
+0

Также соответствует 180 и 800. – aschepler

+0

Добавлены привязки .. –

+0

Использование grep вообще для этого не такая хорошая идея ; он выделит дополнительный список для хранения результатов grep, и он будет продолжать проходить через массив, даже если первый элемент равен 80. –

0

Если вы используете Perl 5.10 или более поздней версии, вы можете использовать smart match оператор ~~:

my $found = (80 ~~ $in_array); 
7

CPAN решение: использовать List::MoreUtils

use List::MoreUtils qw{any}; 
print "found!\n" if any { $_ == 7 } (7,101,80,22,42); 

Если вам нужно сделать МНОГИЕ МНОЖЕСТВА поиска в том же массиве, более эффективным способом является сохранение массива в хэше однажды и поиск в хеше :

@int_array{@int_array} = 1; 
foreach my $lookup_value (@lookup_values) { 
    print "found $lookup_value\n" if exists $int_array{$lookup_value} 
} 

Зачем использовать это решение по альтернативам?

  • Нельзя использовать интеллектуальный матч в Perl до 5.10. Согласно этому сообщению SO by brian d foy] 2, умное совпадение короткое замыкание, поэтому оно так же хорошо, как «любое» решение для 5.10.

  • grep решение проходит через весь список, даже если первый элемент из 1 000 000 длинного списка совпадает. any будет замыкаться на короткое замыкание и выйти из момента, когда будет найдено первое совпадение, тем самым он будет более эффективным. Оригинальный плакат явно сказал «без прокрутки по каждому элементу»

  • Если вам нужно выполнить LOTs lookups, одноразовая стоимость создания хэша делает метод поиска хэша более эффективным, чем любой другой.См this SO post for details

+0

Ну, это зависит от размера массива и количества проверок, которые вам нужно сделать. Анализ внешнего модуля может быть менее эффективным, чем полный 'grep'. –

+0

Также, если эффективность является основной задачей, просто выполните ручную 'foreach' с' last'. –

+2

@kemp - IIRC, List :: MoreUtils имеет реализацию XS. Это быстрее, чем foreach с последним. если использовать собственный Perl, это, вероятно, то, что делает модуль в любом случае. – DVK

3

Еще один способ проверить числа в массиве:

#!/usr/bin/env perl 

use strict; 
use warnings; 

use List::Util 'first'; 

my @int_array  = qw(7 101 80 22 42); 
my $number_to_check = 80; 

if (first { $_ == $number_to_check } @int_array) { 
    print "$number_to_check exists in ", join ', ', @int_array; 
} 

См List::Util.

Смежные вопросы