in reply to Starting foreach at an arbitrary position

Since other people seem to only be suggesting the 'slice' implementation, I will follow in the spirit of Perl, and suggest a persuasive alternative:

for (my $i = 2; $i < @array; $i++) { local *_ = \ $array[$i]; ... use $_ as you would normally use it in foreach() ... }

The "local *_ = \ $scalar" trick makes $_ become an alias to $scalar (really the value in $scalar). This is equivalent to the effect that foreach() has, with the exception that this method does not work for lexical variables. UPDATE: Further explanation: foreach() accepts a lexical iterator variable. local(*) can only be used on global variables.

When would you use this alternative over the slice alternative? I would suggest that the slice alternative be used for all relatively simple operations that involve few array elements (<1000), and that can be easily represented using '..' notation. The slice solution is certainly more common, and therefore, easy to maintain.

The most significant problem with the slice alternative is that array slices are actually a list of scalars specified using a simplified notation. You can easily specify @array[1 .. 1000000], but the result is a temporary list that has 1000000 scalars in it. Unless you have relatively unlimited RAM, the alternative presented above may be for you. (NOTE: I wouldn't consider 100 elements to be large enough to avoid using '..' and an array slice)

A major benefit for the alternative presented above, is that the algorithm used to move through the array can be arbitrarily complicated. Backwards, forwards, skip by 2, etc. .

Have fun... :-)

Replies are listed 'Best First'.
Re^2: Starting foreach at an arbitrary position
by Aristotle (Chancellor) on Jan 18, 2003 at 17:33 UTC
    The point about the advantages of local *_ = \ $array[$i]; is well taken, but I absolutely hate for(;;) loops. It seems like I've made a fencepost error almost every time I wrote one of those. There are very few cases where it's the most appropriate solution. Since for(;;) is implemented in terms of while(){} continue{}, you should use while(){} unless you actually need a very simple continue{} block (and I've never come across such a case). For abitrarily complex index calculation I'd do something like this:
    my $get_next_idx = make_index_iterator(\@array); while(my $i = $get_next_idx->()) { local *_ = \ $array[$i]; # $_ is aliased here }
    (Note how the point about ($_) for BrowserUk's code doesn't apply as $i is an array index, not an array element.)

    Makeshifts last the longest.

Re: Re: Starting foreach at an arbitrary position
by sauoq (Abbot) on Jan 19, 2003 at 04:07 UTC
    The "local *_ = \ $scalar" trick makes $_ become an alias to $scalar (really the value in $scalar). This is equivalent to the effect that foreach() has, with the exception that this method does not work for lexical variables.

    What do you mean when you say "this method does not work for lexical variables?" It will work just fine as a way to iterate over lexically declared arrays as well as global arrays. There is nothing wrong with using a typeglob to alias a lexical, is there?

    I don't think you meant to imply otherwise but that statement confuses me.

    $ perl -Mstrict -wle 'my @lexical = (1..3); for (my $i=0; $i<@lexical; + $i++){ local *_ = \$lexical[$i]; $_ = "foo"} print "@lexical"' foo foo foo

    Update: Upon re-reading that, I'm guessing that you simply mean that you can't use a lexical as the iterator variable.

    -sauoq
    "My two cents aren't worth a dime.";
    

      I think what he meant was that the LHS can't be a lexical variable.


      Warning: Unless otherwise stated, code is untested. Do not use without understanding. Code is posted in the hopes it is useful, but without warranty. All copyrights are relinquished into the public domain unless otherwise stated. I am not an angel. I am capable of error, and err on a fairly regular basis. If I made a mistake, please let me know (such as by replying to this node).

        Well, once you put that little splat on the left hand side, it won't be a lexical. You may be right. I took the "method" he was explaining as an answer to the original question rather than an explanation of aliasing in general. FWIW, I considered the possibility that you suggest and didn't think it was the case. I won't pretend to know though. :-)

        -sauoq
        "My two cents aren't worth a dime.";