How do I read two items at a time in a Perl foreach loop?

前端 未结 19 1424
你的背包
你的背包 2020-12-14 15:12

What I\'m looking for is something like:

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

相关标签:
19条回答
  • 2020-12-14 15:16

    You will probably want to create a simple subroutine to make it work for you.

    I suggest this:

    {
      my $cl_ind = 0;
      sub arrayeach(@) {
        my @obj = @_;
        if(($cl_ind+2) > @obj)
        {
          $cl_ind = 0;
          return;
        }
        $cl_ind+=2;
        return ($obj[$cl_ind-2],$obj[$cl_ind-1]);
      }
    }
    

    The closure makes it work cleanly. To use arrayeach (which works like the hash each without requiring dangerous coercion to an array:

    my @temp = (1,2,3,4,5,6,1,2,3,4,5,6);
    while( ($a,$b) = arrayeach(@temp)) {
      print "A $a AND $b\n";
    }
    

    This is nondestructive.

    0 讨论(0)
  • 2020-12-14 15:16

    another approach, not fully clean, but usable. each creates iterator, you can use it twice. when parameter is classic array, it returns index and value, please read this: https://perldoc.perl.org/functions/each.html

    so, your code can be like this:

    my @array=qw(one two three four five); #five element as unpaired will be ignored
    while (my ($i1,$one,$i2,$two)=(each(@array),each(@array)) {
      #we will use $ix for detect end of array
      next unless defined $i1 and defined $i2; #secure complete end of array
      print "fetched array elements: $one => $two\n";
    };
    

    Example above will not destruct source data, against shift or similar. I hope this we helpful for anyone. of course case with plain iterator is much better.

    0 讨论(0)
  • 2020-12-14 15:16

    I came up with this code to solve a similar requirement:

    sub map_pairs(&\@) {
        my $op = shift;
        use vars '@array';
        local *array = shift;    # make alias of calling array
    
        return () unless @array;
    
        # Get package global $a, $b for the calling scope
        my ($caller_a, $caller_b) = do {
            my $pkg = caller();
            no strict 'refs';
            \*{$pkg.'::a'}, \*{$pkg.'::b'};
        };
    
        # Get index counter size.
        my $limit = $#array/2;
    
        # Localize caller's $a and $b
        local(*$caller_a, *$caller_b);
    
        # This map is also the return value
        map {
            # assign to $a, $b as refs to caller's array elements
            (*$caller_a, *$caller_b) = \($array[$_], $array[$_+1]);
            $op->();    # perform the transformation
        } 
        map { 2 * $_ } 0..$limit;  # get indexes to operate upon.
    }
    

    You use it like so:

    @foo = qw( a 1 b 2 c 3 );
    my @bar = map_pairs { "$a is $b" } @foo;
    

    to get:

    @bar = ( 'a is 1', 'b is 2', 'c is 3' );
    

    I've been meaning to submit to the maintainer of List::MoreUtils, but I don't have an XS version to offer.

    0 讨论(0)
  • 2020-12-14 15:20

    here's an implementation of natatime that doesn't make a copy of the list:

    sub natatime {
      my $n = shift;
      my $list = \@_;
    
      sub {
        return splice @$list, 0, $n;
      }
    }
    
    my $it = natatime(3, qw(1 2 3 4 5 6));
    while ( my @list = $it->() ) {
      print "@list\n";
    }
    
    0 讨论(0)
  • 2020-12-14 15:22

    Risking the necromancy tag, I decided to add one more from Tim Toady's backpack:

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

    Nondestructive, no duplicate lists, no state variables and reasonably terse.

    0 讨论(0)
  • 2020-12-14 15:24

    quick solution for small arrays:

    for ( map {$_*2} 0..@list/2-1 ){
        my ($i, $j) = @list[$_,$_+1];
        print "i: $i, j:$j\n";
    }
    

    some kind oneliner

    data:

    @v = (a=>1, b=>2, c=>3);
    

    this

    print join ', ', map{sprintf '%s:%s', $v[$_], $v[$_+1]} grep {!($_%2)} 0..$#v
    

    or somthing like this

    print join ', ', map {sprintf '%s:%s', @v[$_,$_+1]} map {$_*2} 0..@v/2-1;
    

    result is same

    a:1, b:2, c:3
    
    0 讨论(0)
提交回复
热议问题