【问题标题】:Get next element of array inside a foreach loop in perl without using next/skipping to next iteration of loop在perl的foreach循环中获取数组的下一个元素,而不使用下一个/跳到循环的下一个迭代
【发布时间】:2013-05-17 11:03:04
【问题描述】:

我是 perl 新手,在不重复循环的情况下跳到 foreach 循环内的数组的下一个元素时遇到了一些问题。假设我有以下情况,我正在使用 foreach 循环遍历数组。

 foreach (@lines){  
     ...  
     print "$_";     #print current line  
     if (cond){      #this condition is met by one "line" in @lines  
        #goto next line;  
        $_=~s/expr/substitute_expr/g;     #substitute in the next line  
      }  
     ...
 }

是否可以在 perl 中执行此操作。使用文件处理程序,可以使用 运算符,如下所示

foreach $line (<FILE>){  
    print "$line\n";        #print this line  
    $line = <FILE>;  
    print "$line";        #print next line  
} 

有什么办法可以用数组复制。
有什么办法可以做到这一点 没有 使用 下一个 重复数组

【问题讨论】:

  • next 有什么问题?
  • @Cyx 如果给定的 $line 触发了 ifstatement,并且此 if 语句中使用的代码块需要数组的下一个元素,则 next 无法实现想要的结局。

标签: arrays perl foreach next


【解决方案1】:

你可以使用数组索引:

for my $i (0 .. $#lines) {
    # ...
    print $lines[$i];
    if (cond()) {
        $lines[ $i + 1 ] =~ s/pattern/replace/g;
    }
}

但是,这将在循环的下一次迭代中再次处理“下一个”行。如果你不想这样,你可以使用 C 风格:

for (my $i = 0; $i < $#list ; $i++) {
    # ...
}

更高级的技术是定义一个迭代器:

#!/usr/bin/perl
use warnings;
use strict;


sub iterator {
    my $list = shift;
    my $i = 0;
    return sub {
        return if $i > $#$list;
        return $list->[$i++];
    }
}


my @list = qw/a b c d e f g h/;
my $get_next = iterator(\@list);

while (my $member = $get_next->()) {
    print "$member\n";
    if ('d' eq $member) {
        my $next = $get_next->();
        print uc $next, "\n";
    }
}

【讨论】:

  • 我喜欢你在迭代器中使用了闭包!好的解决方案:通过在迭代器中隔离烦人的索引来保持 while 循环的整洁和清晰。如果您正在解析输出并希望每隔一段时间从“列表”中提取几行,则特别有用。
  • 我喜欢闭包迭代器解决方案,但它的性能与普通的 foreach 循环不同,因为对于任何为零、空字符串或未定义的数组元素,它都会失败。我在下面发布了一个经过编辑的解决方案。
【解决方案2】:

这是对 choroba 闭包答案的修改,适用于所有数组(即包含 0""undef 等值的数组),因此执行起来更像典型的 foreach 循环。

#!/usr/bin/perl
use warnings;
use strict;

#!/usr/bin/perl
use warnings;
use strict;

sub iterator {
    my $list = shift;
    my $i = 0;
    return sub {
       if (defined $_[0] and $i > $#$list){
           return 0;
       }
       elsif (defined $_[0]){
           return 1;
       }
       else{
           return $list->[$i++];
       }
    }
}

my @list = qw/a b c d e f g h 0 1 2 3/;
my $get_next = iterator(\@list);

while ($get_next->("cycle through all array elements")) {
    my $member = $get_next->();
    print "$member\n";
    if ('d' eq $member) {
        my $next = $get_next->();
        print uc $next, "\n";
    }
}

【讨论】:

    【解决方案3】:

    使用计数循环,如下所示:

    use strict;
    use warnings;
    
    my @list = (1, 2, 3);
    # as the item after the last can't be changed,
    # the loop stops before the end
    for (my $i = 0; $i < (scalar @list - 1); ++$i) {
        if (2 == $list[$i]) {
            $list[$i + 1] = 4;
        }
    }
    
    print join ',', @list;
    

    输出:

    perl countloop.pl
    1,2,4
    

    【讨论】:

    • scalar @list - 1@list - 1$#list 相同
    • @mpapec - 因为它们是相同的 - 为什么要评论我使用我最喜欢的那个?
    • 您的 for 循环永远不会遍历最后一个元素。如果是这样,您应该在该行旁边添加评论。
    猜你喜欢
    • 2011-07-03
    • 2012-10-11
    • 2021-08-25
    • 1970-01-01
    • 2015-08-27
    • 1970-01-01
    • 2015-10-02
    • 1970-01-01
    • 2014-12-23
    相关资源
    最近更新 更多