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

I'm having a little trouble following the documentation on pushing. It gives us the example:
for $value (LIST) { $ARRAY[++$#ARRAY] = $value; }
I'm assuming (LIST) should be an array list, and if that's so it would have been nice if they said that in the docs because at first I thought it was a filehandle of some kind.

$ARRAY[..] = $value looks like a hash rather than an array so what's really happening? Are the values stripped from the list, placed into a hash then rewritten back into the list?

And what happens if your list isn't an array but you want to make it one? For example I'm trying to do something like:

while (($this,$that)= each(%list)) { add each $this and $that into the array sort out array by numerics (highest $that (which is always a number) w +ill be on top).
I'm not really complaining but one day when I know enough what I'm talking about I'll try writing some documents on functions like this and make it easier for people to understand (hopefully it's not just me who has problems following them). Thanks monks.

"Age is nothing more than an inaccurate number bestowed upon us at birth as just another means for others to judge and classify us"

sulfericacid

update (broquaint): added a pair of <code> tags

Replies are listed 'Best First'.
Re: array pushing
by Limbic~Region (Chancellor) on Apr 25, 2003 at 22:17 UTC
    sulfericacid,
    From perldoc -f push:
    push ARRAY,LIST Treats ARRAY as a stack, and pushes the values of LIST onto the end of + ARRAY. The length of ARRAY increases by the length of LIST. Has the +same effect as for $value (LIST) { $ARRAY[++$#ARRAY] = $value; } but is more efficient. Returns the new number of elements in the array +.
    Ok - you completely missed the part that says same effect as. The syntax for push is (see top line of documentation):
    push @array , "new value";
    The blurb from the documentation is saying that push treats the array like a stack. Imagine one of those bad cafeteria's that have the plates on a spring loaded stack. You push a new plate onto the stack it gets bigger, you pop one off by pulling the top plate off.

    This example of code is doing the following:

  • For each item in a list (any list not just array), treat each item as $value
  • Find the last element of the array using $#ARRAY, and one to it with ++, and set that equal to $value
  • As a side effect, it returns the new number of elements in the array ( $newcount = push @array , "blah" ), you would get the total number of elements in the array

    That is the same thing as pushing a new plate on the stack.

    I hope this helps - L~R

(jeffa) Re: array pushing
by jeffa (Bishop) on Apr 26, 2003 at 00:20 UTC
    Ahh, what this really boils down to is a code problem (sulfericacid gave me a hint after i inquired about that curious while loop).

    If have you a hash like so:

    my %word = ( 'list' => 3, 'thats' => 1, 'value' => 2, 'an' => 1, 'would' => 1, 'the' => 3, 'at' => 1, 'if' => 2, );
    And you want to sort it by the values, then you shouldn't use a while loop with each. Instead, use a for loop with sort and keys.

    First example - i want to print the above hash sorted by the keys in ascending order:

    print "$_ => $word{$_}\n" for sort keys %word;
    Second example - sort by the values in ascending order:
    print "$_ => $word{$_}\n" for sort {$word{$a} <=> $word{$b}} keys %word;
    What's going on with $a and $b? Those are special built-in variables used for sorting. You should read the docs on sort. Moving on:

    Third example - sort first by the values in descending order this time, and then sort by the keys in ascending order:

    print "$_ => $word{$_}\n" for sort { $word{$b} <=> $word{$a} # sort values desc || # if same, then $a cmp $b # sort keys asc } keys %word ;
    Finally, here is a complete script for your amusement. It reads in some text from the DATA filehandle (for convenience) and tries to filter out "words". These "words" are stored into a hash, and the 'histogram' is printed out and the end. The mystery of $blank is up to you to solve. ;)

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
      Thanks for your help everyone, I greatly appreciate it. It turns out that since I was using a hash to begin with I didn't have to turn it into an array in order to sort it the way I needed. Not sure why I had the crazy idea it had to be an array but the problem was quickly solved when jeffa pointed out I could just sort the hash I was working with.

      When the time comes I'll be prepared to use arrays like this, thanks everyone.

      "Age is nothing more than an inaccurate number bestowed upon us at birth as just another means for others to judge and classify us"

      sulfericacid

        Ahh, but you are using an array to sort with! Consider these:
        print $key for $key sort keys %hash; print $val for $val sort values %hash;
        Sure, the far right side is a hash, but what are keys and values? They are built-in functions (just like sort) that return lists. The trick is what you do with those lists.

        What is the difference between a list and array? Well, you did take The Mad Hatter's advice and read japhy's article, didn't you? Just remember, a lot of folks (including myself) have a hard time understanding that material. Sometimes the concept itself is just too darned difficult for anyone to teach it in an easy to digest manner ... repeated reading / experimentation is how i learn that stuff. Sometimes that revelation doesn't hit you until years have passed. Keep on truckin' ... or change your interest and do something else. ;)

        jeffa

        rinse ... repeat ...
Re: array pushing
by The Mad Hatter (Priest) on Apr 25, 2003 at 22:14 UTC
    Just to note, a filehandle would work because it can act as an array. That's why you can do @lines = <FH>;

    Now, concerning $ARRAY[++$#ARRAY] = $value;. Array elements are accessed by $array[$index]. So to access the second element in the array @array you would write $array[1]. It is a one because array indexes start at 0. Now, the $#ARRAY syntax is a special way of saying @array - 1; basically, it returns the index of the last element in @ARRAY. The ++ increments this value and then uses it as the new index, which it sets equal to $value.

    As for the other question, this should work... Hopefully it gives you an idea of how to do things. Read up on sort if you don't get that part.

    while (($this, $that) = each(%list)) { push @array, $this, $that; } @array = sort { $a <=> $b } @array;

    I hope that helps. You may also want to read the very helpful article "List" Is a Four-Letter Word.

    Added part about the "list into array" thing.

      Actually, the filehandle example you give works not because "a filehandle can act as an array" but because readline returns a list of all lines that can still be read from the filehandle in list context. That is, an operator that works on filehandles has a nice shortcut to get a list of things in one fell swoop.

      Subtle difference, but this is Perl. :)

(jeffa) Re: array pushing
by jeffa (Bishop) on Apr 25, 2003 at 22:22 UTC
    #use strict; #use warnings; @ARRAY = qw(foo bar baz); @LIST = qw(some new items); for $value (@LIST) { $ARRAY[++$#ARRAY] = $value; } print $_,$/ for @ARRAY; __END__ foo bar baz some new items
    Documentation is not required to be easy to understand, just accurate and up to date. Learning books however ...

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    

      jeffa says > Documentation is not required to be easy to understand, just accurate and up to date.

      I'm not sure I agree with this entirely. I would s/not required to be/not necessarily/ and agree. But documentation should strive to be easy to understand. That is its purpose. It should be either easy to understand by being organized in a fashion that facilitates rapid reference (if it's reference documentation) or it should be written in a way that fosters comprehension of a new concept (if it's tutorial documentation). (And thanks by the way for the link to Barnes & Noble's listing of Learning Perl. Did anyone else notice that people who bought this book also bought other Perl books only from O'Reilly as well? It's like no other publisher really can find the mark on this.)

      I think the point you are making is that reference documentation should be somewhat terse so that an experienced reader can easily get to the salient facts without having to wade through a lot of elementary explanations of terms and so forth. (Sorry about this message. I couldn't find my "so called LASER BEAM" when I went to write it. So it's tutorial documentation style rather than reference documentation style.) But being terse doesn't necessarily forbid being easy to understand.

      I think that in the Perl world, because we are so compulsive about writing the smallest number of instructions to get a job done, we try to take the same approach with writing and communicating. It doesn't always work out. And while the effect is not limited at all to the Perl world, there are many fine instances in the Perl documentation of Obfuscated Technical Documentation at the highest form of the art.

      That's what makes Perl Monks more valuable to me than the documentation or any of the existing books about Perl. The things that have been written in conjunction with the understanding that is demonstrated here out of the minds of the community members makes something that really leads me to enlightenment.

      ...All the world looks like -well- all the world, when your hammer is Perl.
      ---v

        Nice post. agentv++ :)

        But, the point i was trying to make was not that reference documentation such as this should be terse and void of elementary explanations ... i was trying to show sulfericacid that one should always try to execute the code in question, munge it up, debug it ... etc. Get involved before you involve others ...

        There is an underlying question that seems to stem from your post ... "is the documentation is question in need of an 'upgrade'?". I don't think so. Besides building the courage to grok 'man pages', there also exists a skill known as search-foo - the ability to find that one piece of documentation that exists, somewhere "out there", that you can understand.

        jeffa

        L-LL-L--L-LL-L--L-LL-L--
        -R--R-RR-R--R-RR-R--R-RR
        B--B--B--B--B--B--B--B--
        H---H---H---H---H---H---
        (the triplet paradiddle with high-hat)
        
Re: array pushing
by blaze (Friar) on Apr 25, 2003 at 22:29 UTC
    lets say you wanted the 2nd element of array @hello to be hi..then you could do something like
    $hello[1] = 'hi';
    thats all this is doing..lets say we have this
    my @first = qw/one two three/; my @second = qw/four five six/; for $value(@first){ $second[++$#second] = $value; }
    so $#second starts out as 2 (the number of elements in $second starting from zero) so the ++$#second is saying start at 3. So during the first loop its basically saying
    $second[3] = $value;
    so we're appending the elements of @first to @second, which in the end will contain 'four five six one two three' in my example..an easier way would have been to just do
    push(@second, @first);
    but i guess the docs were trying to make a point (too lazy to go look for myself (: )..anyway, hope this helps clear things up a bit for you

    -Robert
Re: array pushing
by bart (Canon) on Apr 27, 2003 at 10:46 UTC
    I'm having a little trouble following the documentation on pushing. It gives us the example:
    for $value (LIST) { $ARRAY[++$#ARRAY] = $value; }
    I'm assuming (LIST) should be an array list, and if that's so it would have been nice if they said that in the docs because at first I thought it was a filehandle of some kind.
    Well first, you should understand the syntax of this kind of generic example first. It is pretty common, throughout the docs, that symbolic representations are represented in upper case. For example, in a regexp
    /PATTERN/
    "PATTERN" doesn't really represent the upper case word "PATTERN", but any generic regexp pattern. It's something like a variable, for a code template.

    In the same way, in the code you brought along, "LIST" is any list. It can be @abc or $a, $b, $c or $a, @b, $c or... Anything, really.

    $ARRAY[..] = $value looks like a hash rather than an array so what's really happening?
    You must be thinking of PHP. In Perl, hashes are never used in combination with square brackets. So this is a real array, with numerical indexes.

    Anyway, "@ARRAY", again, represents any kind of array, for example @{$arrayref}. $#ARRAY is the associated "last index" value of this array. I didn't even know you could use it as an Lvalue, for increment. But, why not. Anyway, what this snippet represents is: increment the size of the array by one, and store the value of $value as the new last array item.

    HTH.

      Again I would like to thank everyone for your efforts in understanding this problem at hand. I'll admit I'm still pretty unsure about arrays (I think I understand scalars and hashes much better, but I'm thinking that's probably pretty common) but after using them for a while it'll come to me.

      Thanks for your help everyone.

      "Age is nothing more than an inaccurate number bestowed upon us at birth as just another means for others to judge and classify us"

      sulfericacid