Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Re: Easiest way to do something only on first iteration of loop

by Mr. Muskrat (Canon)
on May 06, 2016 at 22:35 UTC ( [id://1162403]=note: print w/replies, xml ) Need Help??


in reply to Easiest way to do something only on first iteration of loop

Marshall++ for pointing out the most obvious solution. However, since it is possible that you have simplified what you are trying to accomplish, here are three alternatives.You can decide which is best.

sub display_paragraph() { my $aref = shift; my $indentation = shift; my $first_time = 0; # declare and init a flag for my $line (@$aref) { if (++$first_time == 1) { # change and test the flag print ' ' x $indentation; } print "$line\n"; } }
use 5.010; sub display_paragraph() { my $aref = shift; my $indentation = shift; for my $line (@$aref) { state $first_time = 0; # declare and init a flag if (++$first_time == 1) { # change and test the flag print ' ' x $indentation; } print "$line\n"; } }
sub display_paragraph() { my $aref = shift; my $indentation = shift; while (my ($index, $line) = each @$aref) { if ($index == 0) { # test the position print ' ' x $indentation; } print "$line\n"; } }

Replies are listed 'Best First'.
Re^2: Easiest way to do something only on first iteration of loop
by ibm1620 (Hermit) on May 06, 2016 at 23:34 UTC
    My example was only meant to be illustrative -- it does seem that there are times I really need to deal with the first-time (or subsequent-time) condition inside the loop, rather than outside, to avoid duplicating code (also, loops often iterate zero times, in which case you don't want the action to be taken).

    I've tried a shorter version of #1, setting my $next_time = 1 and then testing for (!--$next_time) but that's sort of ridiculous.

    In your second alternative, with the 'state' variable, does the state variable ever become zero again? The perldoc seems to say it is never reinitialized.

    I didn't know about using 'each' with an array, as in your third alternative. That's neat.

    Obviously there's not a brilliantly compact idiom :-)

      Mr. Muskrat++ for other alternatives.

      See State Variable. A a "state" variable is a special kind of "my" variable that is not re-initialized ever again. Its value will persist for the life of the program. in the loop when it is seen again. When it is "out of scope", then next time it comes into scope it is reinitialized. Was new in Perl v5.10.

      See each for arrays. each with this behavior was new in Perl 5.12 and this was also new to me.

      No there is no "magic" short easy syntax for what you want to do in the general case, but you are using a common pattern that is easily recognizable. "Once upon a time, there was a princess...", we know what this story is going to be about! Good variable name like $first_time, etc. provides huge clues that something is special at the beginning. I wouldn't worry much about it.

      Update: My mistake. Thanks to Athanasius for catching this issue. The state variable is never re-initialized, even if it goes out of scope and then comes back into scope. The analogy in the documentation to a "my" variable caused a brain cramp when I read the spec. A state variable is called a "Persistent Private Variable".

        Hello Marshall,

        When it [a state variable] is "out of scope", then next time it comes into scope it is reinitialized.

        Sorry to be pedantic, but no, as the documentation says, it is never reinitialized. Consider:

        use strict; use warnings; use feature qw( say state ); my $x = 42; for (1 .. 2) { for (1 .. 3) { state $x; ++$x; say "\$x = $x"; } say "state \$x is out of scope here"; say "\$x = $x"; }

        Output:

        16:48 >perl 1626_SoPW.pl $x = 1 $x = 2 $x = 3 state $x is out of scope here $x = 42 $x = 4 $x = 5 $x = 6 state $x is out of scope here $x = 42 16:48 >

        When the inner for loop ends, state $x goes out of scope and the $x that is printed is the my $x with wider scope. But when the inner for loop is re-entered, the inner-scope $x (the state variable) retains the value it had previously: it is not reinitialized.

        Hope that helps,

        Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re^2: Easiest way to do something only on first iteration of loop
by GotToBTru (Prior) on May 09, 2016 at 14:31 UTC

    A nice survey of solutions, but as written to the opposite problem than the OP. You indent the first line; he wanted to indent all lines other than the first.

    But God demonstrates His own love toward us, in that while we were yet sinners, Christ died for us. Romans 5:8 (NASB)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1162403]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (4)
As of 2024-04-24 21:15 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found