Is it possible to assign two variables the same data from an array in a Perl foreach loop?
I am using Perl 5, I think I came across something in Perl 6.
Somethi
Here is a module-less way to "loop" by an arbitrary value ($by
) and output the resulting group of elements using an array slice:
#!perl -l
@array = "1".."6";
$by = 3; $by--;
for (my $i = 0 ; $i < @array ; $i += $by ) {
print "@array[$i..$i+$by]";
$i++ ;
}
As a one-liner to test (cut and paste to a Unix shell):
perl -E '@array = "1".."6"; $by = 3; $by--;
for (my $i = 0 ; $i < @array ; $i += $by ) {
say "@array[$i..$i+$by]"; $i++ }'
Output:
1 2 3
4 5 6
If you make $by = 2;
it will print pairs of numbers. To get at specific elements of the resulting slice access it as an anonymous array: (e.g. [@array[$i..$i+$by]]->[1]
).
See also:
Some good responses there, including reference to natatime
which is quite easy to use. It's easy to implement too - it is essentially a wrapper around the splice
solutions mentioned in the responses here.
The following is not the nicest example, but I've been using autobox::Core and made an @array->natatime()
"method" ;-) like this:
use autobox::Core ;
sub autobox::Core::ARRAY::natatime {
my ($self, $by) = @_;
my @copy = @$self ;
my @array ;
push @array, [splice (@copy, 0, $by) ] while @copy ;
if ( not defined wantarray ) {
print "@{ $_ } \n" for @array ;
}
return wantarray ? @array : \@array;
}
The @copy
array is spliced
destructively, but $self
(which is how the @array
in front of the autobox method ->
arrow gets passed to the function) is still there. So I can do:
my @dozen = "1" .. "12" ; # cakes to eat
@dozen->natatime(4) ; # eat 4 at time
my $arr_ref = @dozen->natatime(4) ; # make a reference
say "Group 3: @{ $arr_ref->[2] }" ; # prints a group of elements
say scalar @dozen , " cakes left" ; # eat cake; still have it
Output:
1 2 3 4
5 6 7 8
9 10 11 12
Group 3: 9 10 11 12
12 cakes left
One other approach that also uses a CPAN module (I gave this answer elsewhere but it is worth repeating). This can also be done non-destructively, with Eric Strom's excellent List::Gen module:
perl -MList::Gen=":all" -E '@n = "1".."6"; say "@$_" for every 2 => @n'
1 2
3 4
5 6
Each group of elements you grab is returned in an anonymous array so the individual values are in: $_->[0] $_->[1] ...
etc.
You mentioned Perl6, which handles multiple looping values nicely:
my @qarr = 1 .. 6;
my ($x, $y, $z) ;
for @qarr -> $x , $y , $z { say $x/$y ; say "z = " ~ $z }
Output:
0.5
z = 3
0.8
z = 6
For more on the Perl6 approach see: Looping for Fun and Profit from the 2009 Perl6 Advent Calendar, or the Blocks and Statements Synopsis for details. Perhaps Perl 5 will have a similar "loop by multliple values" construct one day - à la perl5i's foreach :-)