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\";
}
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.
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.
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.
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";
}
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.
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