Table of Contents

Numeric Sorting -- How Sort Really Works

That's easy alphabetical sorting by the keys. If you had a hash of international access numbers like this one:

%countries=('976','Mongolia','52','Mexico','212','Morocco','64','New Zealand','33','France');

foreach (sort keys %countries) {
        print "The key $_ contains $countries{$_}\n";
}

You might want to sort numerically. In that case, you need to understand how Perl's sort function works.

The sort function compares two variables, $a and $b . They must be called $a and $b otherwise it won't work. One chap published a book with stolen code, and he changed $a and $b to $x and $y. He obviously didn't test the program because it would have failed and he would have noticed. And this book was really published ! Don't believe everything you read in books -- but web tutorials are always 100% truthful :-)

Back to sorting. $a and $b are compared, and the result is:

So as long as the sort function gets one of those three values back it is happy. This means we can write our own sort routines, and feed them to sort. For example, we know the default sort is alphabetical. But if we write this:

%countries=('976','Mongolia','52','Mexico','212','Morocco','64','New Zealand','33','France');

foreach (sort supersort keys %countries) {
        print "$_ $countries{$_}\n";
}

sub supersort {
        if ($a > $b) {
                return 1;
        } elsif ($a < $b) { 
		return -1;
	} else { 
		return 0; 
	}
}

then it works correctly. Of course, there is an easier way. The 'spaceship' operator <=> . It does exactly what the supersort subroutine does, namely return 1, -1 or 0 depending on the comparison of two given values.

So we can write the above much more easily as:

%countries=('976','Mongolia','52','Mexico','212','Morocco','64','New Zealand','33','France');

foreach (sort { $a <=> $b } keys %countries) {
        print "$_ $countries{$_}\n";
}

Notice the { } braces, which define the contents as the subroutine sort must use. Pretty short subroutine. There is a companion operator to <=> , namely cmp which does exactly the same thing but of course compares the values as strings, not numbers.Remember, if you are comparing numbers, your comparison operator should contain non-alphas, if you are comparing strings the operator should contains alphas only. And don't talk to strangers.

Anyway, you now have enough knowledge to sort a hash by value instead of keys. Suppose your pointy haired manager bounced up to you and demanded a hash sorted by value ? What would you do ? OK, what should you do ?

Well, we could just sort the values.

foreach (sort values %countries) {

But Pointy Hair wants the keys too. And if you have a value you can't find the key.

So we have to iterate over the keys. But just because we are iterating over the keys doesn't mean to say we have to hand the keys over to sort . What about:

%countries=('976','Mongolia','52','Mexico','212','Morocco','64','New Zealand','33','France');

foreach (sort { $countries{$a} cmp $countries{$b} } keys %countries) {
        print "$_ $countries{$_}\n";
}

beautifully simple. If you want a reverse sort transpose $a and $b .