Поиск первого элемента списка, удовлетворяющего некоторому критерию
Проблема
Требуется найти первый элемент списка, удовлетворяющего некоторому критерию (или индекс этого элемента).
Возможна и другая формулировка — определить, проходит ли проверку хотя бы один элемент. Критерий может
быть как простым («Присутствует ли элемент в списке?»), так и сложным («Имеется список работников,
отсортированный в порядке убывания оклада. У кого из менеджеров самый высокий оклад?»). В простых
случаях дело обычно ограничивается значением элемента, но если сам массив может изменяться, вероятно,
следует определять индекс первого подходящего элемента.
Решение
Перебирайте элементы в цикле fоreach и вызовите
last, как только критерий будет выполнен:
my ($match, $found, $item);
foreach $item (@array) {
if ($criterion) {
$match = $item; # Необходимо сохранить
$found = 1;
last;
}
}
if ($found) {
# Сделать что-то с $match
} else {
# неудачный поиск
}
Чтобы определить индекс, перебирайте все индексы массива и вызывайте last, как только критерий выполнится:
my ($i, $match_idx);
for ($i = 0; $i < @аrrау; $i++) {
if ($criterion) {
$match_idx = $i; # Сохранить индекс
last;
}
}
if(defined $match_idx) {
# Найден элемент $array[$match_idx]
} else {
# Неудачный поиск
}
Комментарий
Стандартных механизмов для решения этой задачи не существует, поэтому мы напишем собственный код
для перебора и проверки каждого элемента. В нем используются циклы fоreach и for, а вызов last
прекращает проверку при выполнении условия. Но перед тем, как прерывать поиск с помощью last,
следует сохранить найденный индекс.
Одна из распространенных ошибок — использование функции
grep. Дело в том, что grep проверяет
все элементы и находит все совпадения; если вас интересует только первое совпадение, этот вариант неэффективен.
Если нас интересует значение первого найденного элемента, присвойте его переменной $match.
Мы не можем просто проверять $item в конце цикла, потому что foreach автоматически локализует
переменную-итератор и потому не позволяет узнать ее последнее значение после завершения цикла.
Рассмотрим пример. Предположим, в массиве @employees находится список объектов с информацией о
работниках, отсортированный в порядке убывания оклада. Мы хотим найти инженера с максимальным окладом;
это будет первый инженер в массиве. Требуется только вывести имя инженера, поэтому нас интересует
не индекс, а значение элемента.
foreach $employee (@employees) {
if ( $employee->category() eq 'engineer' ) {
$highest_engineer = $employee;
last;
}
}
print "Highest paid engineer is: ", $highest_engineer->name(), "\n";
Если нас интересует лишь значение индекса, можно сократить программу — достаточно вспомнить,
что при неудачном поиске $i будет содержать недопустимый индекс. В основном экономится объем кода,
а не время выполнения, поскольку затраты на присваивание невелики по сравнению с затратами на проверку
элементов списка. Однако проверка условия if ($i < @ARRAY) выглядит несколько туманно по сравнению с
очевидной проверкой defined из приведенного выше решения.
for ($i = 0; $i < @ARRAY; $i++) {
last if $criterion;
}
if ($i < @ARRAY) {
# Критерий выполняется по индексу $i
} else {
# Неудачный поиск
}
См. также
Proverte kod v komentariyah gde pro list tam oshibki detskie
Оставить комментарий:
|
|