Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

sort keys question

by treebeard (Acolyte)
on Jul 19, 2001 at 02:12 UTC ( [id://97911]=perlquestion: print w/replies, xml ) Need Help??

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

OK, there is a node out there called

How do I sort a hash (optionally by value instead of key)?

I was wondering how the logic works with the sort? When I write

foreach $invnumctr ( sort{$inv{$a} <=> $inv{$b}} keys %inv) {

how does perl know how to sort the list? How does the comparison work logically? I have included this in my code and i have solved my problem, but I feel uncomfortable not knowing what it is that the code is doing.

Replies are listed 'Best First'.
(jeffa) Re: sort keys question
by jeffa (Bishop) on Jul 19, 2001 at 02:18 UTC
    This can also be found in the cookbook, recipe 5.9:
    foreach my $invnumctr (sort { $inv{$a} <=> $inv{$b} } keys %inv) { print "$invnumctr is $inv{$invnumctr}\n"; }
    It's really quite simple, keys returns the list of keys, and sort takes that list and orders it (via a quick sort) based upon it's argument, an arbitrary code block. $a and $b are special variables that are used by sort, which is a good reason not to use them for other variables in your code.

    Jeff

    R-R-R--R-R-R--R-R-R--R-R-R--R-R-R--
    L-L--L-L--L-L--L-L--L-L--L-L--L-L--
    
Re: sort keys question (boo)
by boo_radley (Parson) on Jul 19, 2001 at 02:46 UTC
    OK.
    let's assume that %inv looks like this :
    (Apple=>10, Peach=>5, Berry=>9, Cobbler=>3, Cherry=>7 )
    Now that that's out of the way, let's break things down.
    foreach $invnumctr ( sort{$inv{$a} <=> $inv{$b}} keys %inv) { the first thing to worry about is the keys statement. that yields an array :
    (Apple, Peach, Berry, Cobbler, Cherry)

    so now the sort takes over -- looking the items from the list above, two at a time, putting one into $a and the other into $b, and using them for hash keys. This might look like :
    $inv{Apple} <=> $inv{Peach} $inv{Peach} <=> $inv{Berry} $inv{Peach} <=> $inv{Cobbler} ...
    and so on. The important thing to remember is that it's still using just the keys to sort on! By the time all is said and done, sort knows that Cobbler's value is less than Peach's value is less than Cherry's value is less than Berry's value is less than Apple's value (no puns, please), and that's what gets passed to foreach. see sort for the full perldoc version, and perlop for the scoop on the spaceship operator.

      The important thing to remember is that it's still using just the keys to sort on!

      Well actually it is sorting numerically on the values not the keys (PS I'm sure this was just a slip of the tongue and would have /msg if you'd been online). Anyway to clarify what boo_radley *meant*

      %inv=( Apple => 10, Peach => 5, Berry => 9, Cobbler => 3, Cherry => 7 ); print "\nSort values numerically in ascending order\n"; foreach $key ( sort {$inv{$a} <=> $inv{$b}} keys %inv) { &print_it } print "\nSort values numerically in descending order\n"; foreach $key ( sort {$inv{$b} <=> $inv{$a}} keys %inv) { &print_it } print "\nSort keys alphabetically in alphabetical order\n"; foreach $key ( sort {$a cmp $b} keys %inv) { &print_it} print "\nNote this is the same as\n"; foreach $key ( sort keys %inv) { &print_it} print "\nSort keys alphabetically in reverse alphabetical order\n"; foreach $key ( sort {$b cmp $a} keys %inv) { &print_it } sub print_it { print "$key\t=> $inv{$key}\n" }

      You will see from the examples that we use <=> for numerical sorts and 'cmp' for alphabetical ones. We sort based on the arguments on each side of these operators. $a is one of the keys whereas $inv{$a} is the value in the $inv hash keyed by $a. You will also note that reversing the position of the arguments reverses the sort order. By default sort uses {$a cmp $b} which is an alphabetical sort in alphabetical order.

      cheers

      tachyon

      s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Re: sort keys question
by grinder (Bishop) on Jul 19, 2001 at 02:47 UTC

    Let's say you have some hash:

    my %h = ( Foo => 73, Bar => 66, Rat => -1 );

    If you say sort keys %h you know will get the order Bar, Foo, Rat, which means when you look through the hash in that order you will find 66, 73, -1. You could also say sort { $a cmp $b } keys %h, but that would be a little redundant.

    In essence, the sort routine is going to compare Foo with Bar, Bar with Rat and Rat with Foo to decide on the order.

    If, however, instead of saying {$a cmp $b} we were to say {$h{$a} <=> $h{$b}}, we would be sorting on the value that Foo et al., point to. So we would be comparing 66 with 73, 66 with -1 and 73 with -1. We have to use the spaceship operator <=> because we are performing numerical comparisons.

    If we were to foreach over the hash with the results of this sort, we would see Rat, Bar, Foo.

    I hope that helps you understand how it works. It is a very useful trick to have around.

    --
    g r i n d e r
Re: sort keys question
by buckaduck (Chaplain) on Jul 19, 2001 at 02:49 UTC
    The only thing I would add is that you seem to wonder about the sort order. That's addressed in the sort documentation; it defaults to a string comparison (cmp) but your example uses a numeric comparison (<=>). See perlop for documentation of these operators.

    buckaduck

Re: sort keys question
by treebeard (Acolyte) on Jul 19, 2001 at 03:07 UTC
    thanks for the responses guys, esp. for holding back on the RTFM comments :)

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (6)
As of 2024-04-24 10:41 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found