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

I am trying to reverse an array's listing order received from glob(); Here's my best attempt but I tend to loose one of my files. By this, I mean I have 10 files in my dir and when line 3 proves it, the tables called show only 9 of them, I guess it got poped and ignored. I tried placing it later in the sub but still got back 9. Is there something else I can use or a different approach to doing this?
perldoc didn't have much help for me on this, unless I am looking it up wrong

Thank you in advance. JayBee

$glob = "../dir/*.txt"; @listoitems = glob( $glob ); print br, 'Found: ', $#listoitems + 1, ' items', br; $i=0; print '<table width="600">'; foreach $item (@listoitems) { $item = pop(@listoitems); $i++; if ($i>9){$i=0;} if ($i =~ /0|2|4|6|8/) { @file=get_data($item); ##process and read the file tab1($file[0], $file[1], $file[2], $file[3], $file[4]); } #end if even# else { @file=get_data($item); ##process and read the file tab2($file[0], $file[1], $file[2], $file[3], $file[4]); } #end if odd# } #end foreach#

Replies are listed 'Best First'.
Re: pop an array
by broquaint (Abbot) on Feb 09, 2004 at 13:37 UTC
    If you want to reverse a list (or a scalar) then the reverse function is pretty well suited e.g
    my @listofitems = reverse glob( '../dir/*.txt' );
    HTH

    _________
    broquaint

Re: pop an array
by Abigail-II (Bishop) on Feb 09, 2004 at 13:51 UTC
    foreach $item (@listoitems) { $item = pop(@listoitems);
    What do you think this will do? You are iterating over an array, and while you are iterating, you not only modify the current element, you also modify the array. This is going to cause havoc. If you want to iterate over an array in reverse order, just use the reverse function.

    Abigail

Re: pop an array
by Vautrin (Hermit) on Feb 09, 2004 at 14:36 UTC

    If you need to reverse the contents of the array and you don't want to use the reverse function, you could do something like this:

    use strict; use warnings; my @foo = @ARGV; # get the array we're reversing # reverse it: my @tempfoo; while (scalar (@foo)) { my $element = pop (@foo); push @tempfoo, $element; } @foo = @tempfoo; # foo has been reversed...

    There are probably a hundred different ways to do it if you want to do it just to do it. But stick with reverse unless you absolutely don't want to. It's much cleaner and easier to understand.


    Want to support the EFF and FSF buy buying cool stuff? Click here.

      Strictly speaking the scalar is unnecessary. An array in a boolean context is true if it has elements and false if it's an empty list.

      $ perl -le '@a = (); @b = (1); print "\@a" if @a; print "\@b" if @b;' @b
        Strictly speaking it isn't necessary. I usually add it for clarity. TMTOWTDI.

        Want to support the EFF and FSF buy buying cool stuff? Click here.
        A reply falls below the community's threshold of quality. You may see it by logging in.
        (This is off-topic, but I never use scalar with @rrays. I use 0+@array. Indeed, most often uses of scalar can be changed to the shorter 0 + something or "" . something)
Re: pop an array
by CountZero (Bishop) on Feb 09, 2004 at 19:58 UTC
    Although Abigail-II already told you, he was perhaps not very clear about the reason why your code was not working as you expected.

    We read in the docs about a foreach loop:

    The foreach loop iterates over a normal list value and sets the variable VAR to be each element of the list in turn.
    and :
    In other words, the foreach loop index variable is an implicit alias for each item in the list that you're looping over..
    So there is no need to stuff your $item variable with a pop-ed value from the @listoitems array. You will not only overwrite what was already in $item, but you will at the same time replace the array-element to which $item was aliased to with the value just pop-ed from the array and you will have shortened the array by one (which is an unescapable side-effect of pop.

    The docs warn you about changing the length of the array you are working with:

    If any part of LIST is an array, foreach will get very confused if you add or remove elements within the loop body, for example with splice. So don't do that.

    Try this little program and you will see how your script affects the array:

    use Data::Dumper; @array = 0 ... 9; foreach $item (@array) { print ++$i . " through the loop\n"; $item = pop @array; print Dumper(\@array); }

    CountZero

    "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

Re: pop an array
by TomDLux (Vicar) on Feb 09, 2004 at 22:20 UTC

    Like they said, you want reverse.

    It took me ages to advance from $#listofitems+1 .... there's a better way: $#arrayname is the index of the last element. C/Java/Pascal programmers do everything based on that. But if what you want is the number of elements in the array, use

    scalar @arrayname
    .

    --
    TTTATCGGTCGTTATATAGATGTTTGCA