my %score = ("barney" => 195, "fred" => 205, "dino" => 30);
my @winners = sort by_score keys %score;
Of course, we aren't really going to be able to sort the hash
by score; that's just a verbal shortcut. You can't sort a
hash! But when we've used sort with hashes
before now, we've been sorting the keys of the hash (in
ASCIIbetical order). Now, we're still going to be sorting the
keys of the hash, but the order is now defined by their corresponding
values from the hash. In this case, the result should be a list of
our three characters' names, in order according to their
bowling scores.
Writing this sort subroutine is fairly easy. What we want is to use a
numeric comparison on the scores, rather than the names. That is,
instead of comparing $a and $b
(the players' names), we want to compare
$score{$a} and $score{$b}
(their scores). If you think of it that way, it almost writes itself,
as in:
sub by_score { $score{$b} <=> $score{$a} }
Let's step through this and see how it works. Let's
imagine that the first time it's called, Perl has set
$a to barney and
$b to fred. So the comparison
is $score{"fred"} <=>
$score{"barney"}, which (as we can see by consulting
the hash) is 205 <=> 195. Remember, now, the
spaceship is nearsighted, so when it sees 205
before 195, it says, in effect: "No,
that's not the right numeric order; $b
should come before $a." So it tells Perl
that fred should come before
barney.
Maybe the next time the routine is called, $a is
barney again but $b is now
dino. The nearsighted numeric comparison sees
30 <=> 195 this time, so it reports that
that they're in the right order; $a does
indeed sort in front of $b. That is,
barney comes before dino. At
this point, Perl has enough information to put the list in order:
fred is the winner, then barney
in second place, then dino.
Why did the comparison use the $score{$b} before
the $score{$a}, instead of the other way around?
That's because we want bowling scores arranged in
descending order, from the highest score of the
winner down. So you can (again, after a little practice) read this
one at sight as well: $score{$b} <=>
$score{$a} means to sort according to the scores, in
reversed numeric order.