Iterating a Foreach loop for dummies...

C

Chris L.

Experienced Perl programmer-
I am running into an issue regarding three Foreach loops- one running
under another.
Specifically:
---------------------------------------------------------------------------------------------------------------------
foreach my $entri(@entry){

foreach my $imm(@imi){

foreach my $seq(@ses){
print "$entri $imm $seq\n";
}
}
}
------------------------------------------------------------------------------------------------------------------------
The outcome of this is the first entry in the @entry array, the first
entry in the @imi array, and then looping these first arrays results
over and over with the entire @ses array.

How can I iterate this so the first element of all three arrays are
printed. Then the second of all three arrays are printed. Then the
third, etc., etc.
I have tried using the next, last, redo and LABELS and cannot figure
this out.
Thank you for your expertise.
Chris
 
X

Xicheng

I am not sure if I understood your question, but if your want to
parallelly print your three arrays, you may try something like:
use List::Util qw(max);
.....
my $imax=max(@a,@b,@c);
foreach my $i (0..$imax) {
print "$a[$i]\t$b[$i]\t$c[$i]";
}
 
M

Matt Garrish

Chris L. said:
Experienced Perl programmer-
I am running into an issue regarding three Foreach loops- one running
under another.
Specifically:
---------------------------------------------------------------------------------------------------------------------
foreach my $entri(@entry){

foreach my $imm(@imi){

foreach my $seq(@ses){
print "$entri $imm $seq\n";
}
}
}
------------------------------------------------------------------------------------------------------------------------
The outcome of this is the first entry in the @entry array, the first
entry in the @imi array, and then looping these first arrays results
over and over with the entire @ses array.

How can I iterate this so the first element of all three arrays are
printed. Then the second of all three arrays are printed. Then the
third, etc., etc.

It's not pretty, but I suppose you could do something like:

<untested>

my $length = length(@entry);
$length = length(@imi) if length(@imi) > $length;
$length = length(@ses) if length(@ses) > $length;

for my $i (0..$length) {
print $entry[$i] if $entry[$i];
print $imi[$i] if $imi[$i];
print $sms[$i] if $sms[$i];
print "\n";
}

You could clean the above up a lot if you know that all the arrays are the
same length.

Matt
 
M

Matt Garrish

Matt Garrish said:
It's not pretty, but I suppose you could do something like:

<untested>

my $length = length(@entry);
$length = length(@imi) if length(@imi) > $length;
$length = length(@ses) if length(@ses) > $length;

for my $i (0..$length) {

You'd definitely want to lose 1 from that count first, though. See xicheng's
post for a nicer way to get the max value.

Matt
 
M

Matt Garrish

Ugh! And I just noticed I wrote length instead of scalar! I knew I should
have tested. Would have saved me the follow-ups...
 
P

Paul Lalli

Chris said:
Experienced Perl programmer-
I am running into an issue regarding three Foreach loops- one running
under another.
Specifically:
---------------------------------------------------------------------------------------------------------------------
foreach my $entri(@entry){

foreach my $imm(@imi){

foreach my $seq(@ses){
print "$entri $imm $seq\n";
}
}
}
------------------------------------------------------------------------------------------------------------------------
The outcome of this is the first entry in the @entry array, the first
entry in the @imi array, and then looping these first arrays results
over and over with the entire @ses array.

How can I iterate this so the first element of all three arrays are
printed. Then the second of all three arrays are printed. Then the
third, etc., etc.

#!/usr/bin/perl
use strict;
use warnings;
use List::MoreUtils qw/each_array/;

my $each = each_array(@entry, @imi, @ses);
while (my ($entri, $imm, $seq) = $each->()){
print "$entri, $imm, $seq\n";
}
__END__
 
U

usenet

Chris said:
How can I iterate this so the first element of all three arrays are
printed. Then the second of all three arrays are printed. Then the
third, etc., etc.

You can use the for_each function of the List::MoreUtils module, which
will let you process as many arrays as you please:

#!/usr/bin/perl
use strict;
use List::MoreUtils qw{each_array};

my @a = qw{A B C D};
my @b = qw{a b c d e f g};
my @c = qw{1 2 3 4 5 6};

my $each = each_array(@a, @b, @c);
while ( my ($a, $b, $c) = $each->() ) {
print "$a, $b, $c\n";
}

__END__
 
A

Anno Siegel

You would do us all a favor if you put your reply after the question,
not on top of the whole posting. Interleave it with the quoted text.
If applicable, trim the quoted text to the parts you are replying to.

I have rearranged the posting accordingly.

Xicheng said:
Chris L. wrote:
Experienced Perl programmer-
I am running into an issue regarding three Foreach loops- one running
under another.
Specifically:
-------------------------------------------------------------------------
foreach my $entri(@entry){

foreach my $imm(@imi){

foreach my $seq(@ses){
print "$entri $imm $seq\n";
}
}
}
--------------------------------------------------------------------------

[...]
How can I iterate this so the first element of all three arrays are
printed. Then the second of all three arrays are printed. Then the
third, etc., etc.
I am not sure if I understood your question, but if your want to
parallelly print your three arrays, you may try something like:
use List::Util qw(max);
....
my $imax=max(@a,@b,@c);

This isn't right. It takes the maximum of all list elements from
@a, @b and @c combined. Since you are running without warnings,
(yes, I know why) the non-numeric elements get passed over without
comment. Incidentally the maximum numeric element is 6, which
happens to be the right answer.

This is an object lesson on why one should switch off only the warnings
that need it, in the smallest possible scope.

Even if max() did take its arguments in scalar context (as you appear
to have assumed) the index would come out one too high.

my $imax = max( $#a, $#b, $#c);

is correct.
foreach my $i (0..$imax) {
print "$a[$i]\t$b[$i]\t$c[$i]";
}

Here is an alternative that doesn't use indexing:

my @l = \ ( @a, @b, @c);
while ( grep @$_, @l ) {
no warnings 'uninitialized';
print join( "\t", map shift @$_, @l), "\n";
}

That destroys @a, @b and @c. If that's a problem, make that

my @l = ( [ @a], [ @b], [ @c]);

If grep() in the loop control is too inefficient,

for ( 0 .. max( map $#$_, @l) ) {

can still be used.

Anno
 
X

Xicheng

Anno said:
This isn't right. It takes the maximum of all list elements from
@a, @b and @c combined. Since you are running without warnings,
(yes, I know why) the non-numeric elements get passed over without
comment. Incidentally the maximum numeric element is 6, which
happens to be the right answer.
my $imax = max( $#a, $#b, $#c);
yep, you are right, I tested it on the command line, so did not notice
the errors. this 'max' function takes a list argument, and thus
flattens three arrays. Thank you very much for correcting me.. Have a
good day,
Xicheng
 
T

Tassilo v. Parseval

Also sprach (e-mail address removed):
You can use the for_each function of the List::MoreUtils module, which
will let you process as many arrays as you please:

As a matter of fact it will let you process at most 31 arrays due to the
way Perl prototypes work.

Tassilo
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,756
Messages
2,569,540
Members
45,025
Latest member
KetoRushACVFitness

Latest Threads

Top