ww has asked for the wisdom of the Perl Monks concerning the following question:

This is what I believe to be the essence of the question: How the dickens do I dump out of an inner loop, increment what TFM calls " the foreach loop index variable," and continue looking for lines where $values[1], the 'quantity' element of the array, != 0?
ie, when quant is zero, don't print ANY member of the array in which it appears; when quant is numeric and non-zero, print the entire array (and some html and other content) to the resultant page? (updated here as of 1340G, 14 Apr with further info that I hope provides additional clarification added in UPDATE, below)

simplified from my problemchild, AKA script1 (which demonstrates that my nested loop fu is clearly deficient):

#!/usr/bin/perl -wT use strict; use CGI qw(:standard escapeHTML); use vars qw ( way too many of them); my $query = CGI->new(); @names = $query->param; ... (preparatory material including a heredoc for the top of the page +to be returned) foreach $name (@names) { @values = $query->param( $name ); for $values(@values) { if ( $values[1] =~ /^0$/ ){ last; } # Note 1 &untaint($name, $values ); # ... Test and print html-table rows, if $values[1] != 0 } } }
Note 1: I tried this here and in untaint(), with and without a LABEL: at the start of the foreach; in the snipped code; and also tried using "next" and "redo" instead of "last" etc...

The code addressed here gets its input from a form in an .html page created by another script (call that one "script0") which produces the page with the form in which customers can draft an order. "script0" uses CGI qw(:standard escapeHTML); as does this one. (For purists, I opted to use a pair of arrays rather than a hash for a variety of perhaps-not-so-great-reasons.) In any case, the @values array from script0's form has a variety of name=value pairs, of which the relevant set looks like this:

I0=nameofplant Q0=\d+ P0=\d+\.[\d]{2} IT0=\d+\.[\d]{2} I1=anotherplant Q1=\d+ P1=\d+\.[\d]{2} IT1=\d+\.[\d]{2} etc...
(Those form elements which don't conform to this pattern are handled separately)

The snipped "test and print..." code very satisfactorily prints the input data... I have NOT figured out how -- when the quantity in $values[1] is zero -- to drop out of bypass the inner loop and begin the next iteration of the foreach on @names.

Neither TFM ...nor the tutorial examples I've found address this in a manner I so far been able work thru and understand. Thus, I seek the wisdom and teaching capabilities of the Monastery.

UPDATE2 (4/21): tried to work with revdiablo's and Herkum's replies and now realize, my info still insuff.

I'm now getting the elements of the form into two separate arrays, like this (yep, only the LABELing is really new):

my $query = CGI->new(); @names = $query->param; ... NAMES: for $name (@names) { $values = $query->param( $name ); if ( $flag == 0 ) { #set the first time thru for special purpos +e data &checkacct(); # which is formatted differently than the r +est... next NAMES; } else { &untaint( $name, $values ); &tohtml( $name, $values ); } }
and my sub tohtml looks like this (the I\d+ run from 0 .. 700+):
if ( $name =~ /^I\d+$/ && $values =~ /[A-Za-z\s_\'\-\.]+/ ) { #I\d+ + print "<tr>\n<td><input type='hidden' name=\"" . $name . " +\" value=\"" . $values . "\"><span class='b'>" . $name . "</span> &nb +sp; " . $values . "<\/td>\n"; # start new row next; } elsif ( $values =~ /^[\d]+$/ && $name =~ /^Q\d+$/ ) { # Q0, +Q1 print "<td style='text-align:center;'><input type='hidden' + name=\"" . $name . "\" value=\"" . $values . "\">Quant: <span class= +'b'>" . $values . "</span></td>\n"; next; # plus 4 more for P\d+ and IT\d+ cases and another pair of speci +al cases
As you can see, I've created a monster; right now, my thought of taming it leans toward creating a hash at the top of tohtml to capture the I\d and then blow it away IF the $value in Q\d+ is 0. (IOW,I want to avoid sending back to the user the items s/he did NOT order.) If Q\d+ is zero then I can rewrite tohtml to return to main at which time next NAMES and a judicious shift or two should take me to testing a new row.

So does this make sense?

UPDATE: revdiablo's question highlights my missing logic:

because the snipped code is printing stuff like...

"<tr><td>ID: " . $name . " $values "; #(where the inner loop is at [0] +) " </td><td>Quantity: " . $values[1];

...I need to test $values[1]==0 before the inner loop starts, to avoid ill-formed and ill-nested html, and -- more pertinent to my project -- to spit out a page which OMITS those items which the user did not order. IOW, I want the next or last in the test of $values[1], to redirect program flow to the next $name, rather than the next $values[n] which entails discovering that the row should have been omitted only after it has already has already emitted the first cell of a new table-row.

</ long-winded update>

Replies are listed 'Best First'.
Re: Exiting the inner loop of a nested loop
by Herkum (Parson) on Apr 14, 2006 at 00:58 UTC

    Sounds what you are look for is last() but you need a label to go with to exit out of a multiple loops that you are in, this is a sample that should give you the idea,

    LOOP: foreach my $no (@nos) { foreach my $counter (@counters) { last LOOP if $counter > 100; } }
      Thank you

      ... but I had tried that (see "Note 1").

      As nearly I can see, I was using basically your syntax, but that has the effect of ALLOWING the inner loop's processing of lines in which $values[1] is zero... which is what I'm trying to avoid. Apologies for the lack of clarity in OP.

Re: Exiting the inner loop of a nested loop
by revdiablo (Prior) on Apr 13, 2006 at 23:38 UTC

    I'm not sure I fully understand your question, but if I read it correctly, I think you might just be looking for next:

    for my $digit (1 .. 3) { for my $char ('a' .. 'c') { next if $char eq 'b'; print "$digit $char\n"; } }

    Or am I missing something?

    Update: I just noticed you said you tried next, as well as last and redo, but you never really explained why those didn't work for you, what they did that you weren't expecting, etc. Can you give further clarification?

Re: Exiting the inner loop of a nested loop
by revdiablo (Prior) on Apr 14, 2006 at 17:45 UTC

    Ah, your update definitely makes it more clear. You're not going to be able to accomplish this by printing and checking at the same time. You'll have to do two passes: one to check for any values that you want to avoid, and another to print out all the values from the ones that are deemed ok. Here's a quick example:

    my @num_lists = ( [ 0 .. 4 ], [ 5 .. 9 ], [ 10 .. 14 ], [ 15 .. 19 ], ); OUTER: for my $list (@num_lists) { for my $num (@$list) { if ($num % 10 == 0) { print "Skipping $list\n"; next OUTER; } } for my $num (@$list) { print "From $list: $num\n"; } }

    Or you can use grep, which still just loops on the values, but might look a bit cleaner to some:

    my @num_lists = ( [ 0 .. 4 ], [ 5 .. 9 ], [ 10 .. 14 ], [ 15 .. 19 ], ); for my $list (@num_lists) { next if grep { $_ % 10 == 0 } @$list; for my $num (@$list) { print "From $list: $num\n"; } }