如何在Perl foreach循环中一次读取两个项目?

Sea*_*agh 35 perl loops

我正在寻找的是:

@list = qw(1 2 3 4 5 6);
foreach (@list) {
  #perl magic goes here 
  print "i: $i, j:$j\n";
}
Run Code Online (Sandbox Code Playgroud)

收益:

i:1, j:2
i:3, j:4
i:5, j:6
Run Code Online (Sandbox Code Playgroud)

为了回应下面的一个非常好的建议,我需要指定此脚本将在其他人的构建服务器上运行,并且我不允许使用CPAN中的任何模块.仅限标准Perl.

mir*_*rod 38

我认为正确的方法是使用来自List :: MoreUtils的natatime:

来自文档:

natatime BLOCK LIST

创建一个数组迭代器,用于一次循环一个$n项目块中的数组.(n一次,得到它?).一个例子可能是一个比我用文字更好的解释.

例:

 my @x = ('a' .. 'g');
 my $it = natatime 3, @x;
 while (my @vals = $it->())
 {
     print "@vals\n";
 }
Run Code Online (Sandbox Code Playgroud)

这打印

a b c
d e f
g

执行List::MoreUtils::natatime:

sub natatime ($@)
{
    my $n = shift;
    my @list = @_;

    return sub
    {
        return splice @list, 0, $n;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,foreach和natatime之间略有不同.foreach更快,内存消耗更少(不会像natatime内部那样复制数组)并允许数组成员修改,例如foreach my $ a(@x){$ a ++}与$ _ ++ foreach @x相同 (2认同)
  • 如果确实如此,natatime不需要复制列表:my $ list =\@_; 然后是:拼接@ $ list,0,$ n; (2认同)

And*_*ett 20

我会用拼接.

my @list = qw(1 2 3 4 5 6);
while(my ($i,$j) = splice(@list,0,2)) {
  print "i: $i, j: $j\n";
}
Run Code Online (Sandbox Code Playgroud)


Jac*_* M. 16

我想你想要以不同的方式做到这一点.试试这个:

while (scalar(@list) > 0) {
    $i = shift(@list);
    $j = shift(@list);
    print "i: $i, j:$j\n";
} 
Run Code Online (Sandbox Code Playgroud)

请记住,这将破坏列表,但它将适用于那个小循环.


Bra*_*ert 16

设置一些测试数据,然后导入say:

use Modern::Perl;
use List::AllUtils qw'zip';

my @array = zip @{['a'..'z']}, @{[1..26]} ;
Run Code Online (Sandbox Code Playgroud)

使用增量变量进行简单循环.

    {
      my $i = 0;
      while(
        (my($a,$b) = @array[$i++,$i++]),
        $i <= @array # boolean test
      ){
        say "$a => $b";
      }
    }
Run Code Online (Sandbox Code Playgroud)

循环使用.List::Pairwise  (pair)

    use List::Pairwise qw'pair';

    for my $pair (pair @array){
      my($a,$b) = @$pair;

      say "$a => $b";
    }
Run Code Online (Sandbox Code Playgroud)

使用,一次循环数组2 .List::MoreUtils  (natatime)

    use List::AllUtils qw'natatime';

    my $iter = natatime 2, @array;
    while( my($a,$b) = $iter->() ){
      say "$a => $b";
    }
Run Code Online (Sandbox Code Playgroud)

将其强制转换为哈希值,然后遍历键.如果你不关心订单,这很有用.

    {
      my %map = @array;
      for my $key (keys %map){
        my $value = $map{$key};
        say "$key => $value";
      }
    }
Run Code Online (Sandbox Code Playgroud)


cha*_*aos 10

不幸的是,最接近的等同物是老派:

for(my $ix = 0; $ix <= $#list; $ix += 2) {
    my $i = $list[$ix];
    my $j = $list[$ix + 1];
    print "i: $i, j:$j\n";
}
Run Code Online (Sandbox Code Playgroud)

我更喜欢Jack M的答案,但是我会用更性感的Perl来写它:

while(@list) {
    my $i = shift @list;
    my $j = shift @list;
    print "i: $i, j:$j\n";
}
Run Code Online (Sandbox Code Playgroud)

  • ()循环的标准+1.一些控制结构是经典的,因为它们工作=). (2认同)

bri*_*foy 7

如果我只能使用没有模块的标准Perl,我可能会下降到一个C风格的for循环,数量为2:

for( my $i = 0; $i < @array; $i += 2 ) {
    my( $i, $j ) = @array[ $i, $i+1 ];
    ...
    }

但是,如果您想从其中一个无法使用的模块中获得某些东西,您可以将该模块添加到您的代码中.如果您可以编写代码,则可以使用模块.您可能只需要在模块中包含您在@INC适当设置时提供的所有代码.这是inc :: Module :: InstallPAR的基本思想.

我花了很多时间使用构建系统来创建自己的CPAN存储库,从其私有CPAN安装其依赖项,然后测试代码.拥有构建服务器场并不排除使用模块; 这是当地的政策.然而,即使有可能,这在所有情况下都没有意义.


Zan*_*ano 6

冒着被挂上死灵标签的风险,我决定从 Tim Toady 的背包里再添加一个:

for (0 .. $#list) {
    next if $_ % 2;
    my ($i, $j) = @list[$_, $_ + 1];
    say "i:$i, j:$j";
}
Run Code Online (Sandbox Code Playgroud)

非破坏性、没有重复列表、没有状态变量并且相当简洁。