优雅的方式捕获“for循环到达最后一个元素”的情况?

4
有时候在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;
  }
}
# <-----

有没有一种优雅的方式-可能是一个重载关键字-来处理“for循环到达最后一个元素”?有什么可以放在箭头上面的东西吗?

我可以想到一些方法来解决这个问题,比如创建/设置一个额外的$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";
}

这将使得测试更加直观易懂。


对于我的 $animal (@animals, "not $input") } ;-) - choroba
2
但是认真地说,使用 List::Util 中的 first - choroba
哈哈,我喜欢第一个建议,但我一定会尝试“第一个”建议。像往常一样,阅读文档是有益的。 - Greg Kennedy
if(grep(/$input/, @animals)){ true clause } else { equivalent of finally } - dawg
5个回答

4
您可以像下面这样使用标记块包装您的循环:
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";
}

2

这里并不是最好的解决方案,但有时通过遍历索引可以帮助解决问题。

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

然后,您可以检查索引是否为0(第一次遍历)或$#a(最后一次遍历)。


1

只需在循环中设置一个变量,以便您可以检查它是否已被设置并在以后采取行动:

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所说,只需使用List::Util中的first(或any)函数即可。或者如果您将检查很多输入,则更容易检查哈希表。

my %animals = map { ($_ => 1) } qw/cat dog horse/;
print exists $animals{$input} ? "Ah, yes, an $input is an animal!\n" : "no animal found\n";

1

我会保持传统,使用一个众所周知的C语言习惯用法(将for循环拆分为第一条语句和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";
}

因此,“抱歉,我不确定狮子是不是动物”这样的话会很自然。 希望这有所帮助。问候,M。

1

首先是最小的开销;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
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接