Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

returning to the outer loop

by Anonymous Monk
on Sep 20, 2018 at 21:03 UTC ( #1222748=perlquestion: print w/replies, xml ) Need Help??

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

This is greatly simplified - I hope it makes sense. :)

I am trying to loop over rows of an array doing a test. If the test fails, I want to go all the way back to the outer loop, which the documentation suggests will work only with foreach.

#!/usr/bin/perl -w use strict; my @x = ( ['aaaaa', 'bbbbb', 'ccccc', 'ddddd',], ['eeeee', 'fffff', 'ggggg', 'hhhhh',], ['iiiii', 'jjjjj', 'kkkkk', 'lllll',], ); for my $i (1 .. 1000) { for my $a (@x) { my $ifails = 0; for my $j (0 .. (scalar @$a) - 1 ) { <get external data string for pattern matching here, put i +n $c> if ($c =~ /$a->[$j]/) { $ifails++; } } if ($ifails > 1) { want to go to outer loop here, and not proc +ess the next (and subsequent) row(s) } } }

Is there some way of doing that? Note that in the actual application, I do have more more processing below the inner loop, so a "last" statement at the test doesn't work.

Thank you in advance.

Replies are listed 'Best First'.
Re: returning to the outer loop
by GrandFather (Sage) on Sep 20, 2018 at 21:40 UTC

    Named blocks used to be the GOTO answer for this sort of problem, but goto is frowned on because it tends to obscure code flow. Often there are better ways to structure your code so that you don't need an explicit equivalent of goto. One way to do that is to place your nested loops in a sub that is called from the outer loop.

    Consider:

    #!/usr/bin/perl -w use strict; my @kPatterns = ( ['aaaaa', 'bbbbb', 'ccccc', 'ddddd',], ['eeeee', 'fffff', 'ggggg', 'hhhhh',], ['iiiii', 'jjjjj', 'kkkkk', 'lllll',], ); for my $test ('yyjjjjjxx', 'ddddd') { my $match = scan($test); print "Matched $test using $match\n" if $match; } sub scan { my ($test) = @_; for my $patternList (@kPatterns) { for my $pattern (@$patternList) { return $pattern if $test =~ $pattern; } } return ; }

    Prints:

    Matched yyjjjjjxx using jjjjj Matched ddddd using ddddd
    Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond
      Hi GrandFather,

      I upvoted your very good post, but I have to disagree somewhat with this:

      Named blocks used to be the GOTO answer for this sort of problem, but goto is frowned on because it tends to obscure code flow.
      Many years ago, I had a CS professor who (mildly) criticized my code (but still gave me a good mark) because I was using constructs similar to next, last and return to exit early from a loop because, he claimed, this was akin to (an evil) GOTO. I disagreed moderately with him at the time, and, with three decades of experience in between, I still disagree, much more strongly, with this view today.

      In the debate that followed the famous Go to statement considered harmful article (https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf) by E. Dijkstra (with a title staged to polemicize chosen by N. Wirth), Donald Knuth (Structured Programming with go to Statements, http://pplab.snu.ac.kr/courses/adv_pl05/papers/p261-knuth.pdf) argued for a more balanced view making (among other things) a distinction between goto forward and goto backward (I'm simplifying quite a bit). Goto backward, he admitted, are often bad because they pave the way for spaghetti code. But goto forward, he said, make sense in many situations. Most of us don't use goto nowadays (at least not in Perl, except possibly and quite rarely for the different goto &NAME form), but next and last statements were invented as a form of healthy structured programming goto forward to exit early from a loop. I agree with Knuth on that (I'm just saying that to state what I think, but, of course, I realize that no one cares about what I think about D. Knuth's arguments on the subject).

      In brief, I really don't think that named blocks tend to obscure code flow (contrary to goto statements). I think they usually are a very natural and clean way to exit early from a loop and that alternatives often tend to be more complicated.

        I somewhat agree that early exits using named blocks has a place. However there is very often benefit in terms of understanding the intent of code from wrapping "complicated" stuff up in a sub. The immediate benefit is that you can understand the surrounding code providing a context for a chunk of named work. If the name is good understanding both the calling context and the called code should be easier and you don't have to understand everything at the same time.

        So, a small part of my reply is "don't use goto", but most of it is "refactor into simple digestible chunks".

        Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond
        I agree, next and last to named blocks in order to exit multi-level loops is perfectly fine. Using the obscure next and last feature that it will jump through subroutine call boundaries, on the other hand, is evil. Yeah.
      ...but goto is frowned on...

      or in other words:
      "... not for the faint of heart (nor for the pure of heart) ..."
      Programming Perl 3rd Edition, page 160.

      This is interesting to me. For someone like me, whose first language was Apple BASIC, I find the loop labels easier to follow and I don't understand why others feel it "obscures" the flow. I find the use of labels to be more clear, actually.

      $PM = "Perl Monk's";
      $MCF = "Most Clueless Friar Abbot Bishop Pontiff Deacon Curate Priest";
      $nysus = $PM . ' ' . $MCF;
      Click here if you love Perl Monks

        The issue with goto based code is that it becomes almost impossible to tell how you get from one point in the code to another which obscures the relationship and intended ordering of the code. Spaghetti coding (using gotos) just doesn't scale well. For a couple of handfuls of code it's OK, but by the time you need to take your shoes and socks off the code starts to lose structure making it hard to understand code flow.

        Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond

        ...because you can fall out of the loop, and have no idea logically where you remain.

Re: returning to the outer loop
by Your Mother (Bishop) on Sep 20, 2018 at 21:20 UTC

    Named blocks should be what you want (code is lightly tested). Generally shouldn’t use single letter var names, even for dummy code and $a and $b should really never be used outside sorting where they have special meaning.

    use strict; use warnings; my @x = ( ['aaaaa', 'bbbbb', 'ccccc', 'ddddd',], ['eeeee', 'fffff', 'ggggg', 'hhhhh',], ['iiiii', 'jjjjj', 'kkkkk', 'lllll',], ); my $tolerance = 1; STEVE: for my $outer ( 1 .. 5 ) { TONY: for my $some_x ( @x ) { my $fail = 0; BRUCE: for my $just_this ( @{$some_x} ) { my $c = "..."; # ... get string for pattern matching here. $fail++ if $c =~ /\Q$just_this/; next STEVE if $fail > $tolerance; } } }

    Update: In anything but straightforward, single-screen-of-code cases, I agree with GrandFather below.

      > In anything but straightforward, single-screen-of-code cases,

      What about meaningful lable-names, STEVE? ;-)

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

        Dude… It’s Captain America, Iron Man, and the Hulk. I dare you to find something more meaningful! To me. After six beers, binging all the Marvel movies on Netflix.

        #!/usr/bin/env YI-BAM-BE!

      Not often I disagree with Your Mother, but I have to here.

      I find it's always advisable to avoid jumping around whenever possible, and it's always almost possible to avoid doing so per your post here.

        But I’d already updated to say GrandFather’s approach was better before you posted… *sniff* sniff* :'{

        So, you really did agree! :P

Re: returning to the outer loop
by nysus (Vicar) on Sep 20, 2018 at 21:30 UTC
Re: returning to the outer loop
by Marshall (Abbot) on Sep 20, 2018 at 21:25 UTC
    I am unsure about what you are trying to accomplish. I of course can't run your code as an example. I just didn't understand it.

    UPDATE: OMG, I got along the wrong track because of your original code which appeared to have several nested loops. The right Perl thing to "exit a single loop" is: last. You need a Label to jump a couple of levels up! But not here! Sorry about the confusion!

    #!/usr/bin/perl use warnings; use strict; my @x = ( ['aaaaa', 'bbbbb', 'ccccc', 'ddddd',], ['eeeee', 'fffff', 'ggggg', 'hhhhh',], ['iiiii', 'jjjjj', 'kkkkk', 'lllll',], ); #@x is a 2D array, an AoA (Array of Array) OUTER: for my $row_ref (@x) { for my $element (@$row_ref) { # call exit(1) to competely stop! # with error code 1 if ($element eq 'ggggg') { print "stop seen\n"; next OUTER; #last; would work here } else { print "$element\n"; } } } __END__ Prints: aaaaa bbbbb ccccc ddddd eeeee fffff stop seen iiiii jjjjj kkkkk lllll
    See also Perl "redo"....

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1222748]
Approved by nysus
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (3)
As of 2020-02-23 02:44 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    What numbers are you going to focus on primarily in 2020?










    Results (102 votes). Check out past polls.

    Notices?