Элегантный способ поймать "для цикла дошел до последнего элемента"? - PullRequest
0 голосов
/ 22 декабря 2018

Иногда в Perl я пишу цикл for / foreach, который перебирает значения для проверки значения по списку.После первого попадания цикл может завершиться, так как мы выполнили условия моего теста.Например, этот простой код:

my @animals = qw/cat dog horse/;

foreach my $animal (@animals)
{
  if ($input eq $animal)
  {
    print "Ah, yes, an $input is an animal!\n";
    last;
  }
}
# <-----

Есть ли элегантный способ - может быть, перегруженное ключевое слово - обрабатывать "для цикла, достигшего последнего элемента"?Что-то, что можно поместить на стрелке выше?

Я могу придумать способы сделать это, например, создать / установить дополнительную переменную $found и протестировать ее в конце .... Но я надеялся, что Perl мог бы иметьчто-то еще встроенное, например:

foreach my $animal (@animals)
{
  if ($input eq $animal)
  {
    print "Ah, yes, an $input is an animal!\n";
    last;
  }
} finally {
  print "Sorry, I'm not sure if $input is an animal or not\n";
}

, что сделало бы этот тест более интуитивным.

Ответы [ 5 ]

0 голосов
/ 01 февраля 2019

Сначала будет меньше всего накладных расходов;eval избегает необходимости вкладывать все это в if-блоки;Новая строка, потому что вам, вероятно, все равно, на какой линии было не животное.

eval
{
  my $found = first { check for an animal } @animalz
  or die "Sorry, no animal found.\n";

  # process an animal

  1
}
// do
{
  # deal with non-animals
};
0 голосов
/ 16 января 2019

Я бы оставил это в Old School и использовал бы хорошо известную C-идиому (цикл for разделен на 1-й оператор и цикл while).

#!/usr/bin/env perl

use strict;
use warnings;

my $input = 'lion';

my @animals = qw/cat dog horse/;

my $index = 0;

while ($index < scalar @animals) {
    if ($animals[ $index++ ] eq $input) {
        print "Ah, yes, an $input is an animal!\n";
        last;
    }
}

if ($index == scalar @animals) {
    print "Sorry, I'm not sure if $input is an animal or not\n";
}

Таким образом, "Извините, яЯ не уверен, является ли лев животным или нет "придет очень естественно.Надеюсь это поможет.С уважением, М.

0 голосов
/ 22 декабря 2018

Просто установите в цикле переменную, чтобы вы могли проверить, была ли она установлена, и выполните ее позже:

my $found;
foreach my $animal (@animals) {
    if ($input eq $animal) {
        $found = $animal;
        last outer;
    }
}
print defined $found ? "Ah, yes, an $input is an animal!\n" : "no animal found\n";

Но для этой конкретной проблемы, как говорит @choroba, просто используйте first(или any) функция из List :: Util.Или, если вы будете проверять множество входных данных, проще проверить хеш.

my %animals = map { ($_ => 1) } qw/cat dog horse/;
print exists $animals{$input} ? "Ah, yes, an $input is an animal!\n" : "no animal found\n";
0 голосов
/ 23 декабря 2018

Это не лучшее решение, но иногда оно помогает перебирать индексы.

for my $i (0..$#animals) {
    my $animal = $animals[$i];
    ...
}

Затем вы можете проверить, является ли индекс 0 (первый проход) или $#a (последний проход).

0 голосов
/ 22 декабря 2018

Вы можете обернуть свой цикл с помеченным блоком, например, так:

outer: {
    foreach my $animal (@animals) {
        if ($input eq $animal) {
            print "Ah, yes, an $input is an animal!\n";
            last outer;
        }
    }
    print "no animal found\n";
}
...