Sorting Lists

You've already seen how to sort a list, for example, the keys in a hash, using the sort function:

@keys = sort keys %hash;

By default, the sort function sorts a list in ASCII order. To sort a list of numbers in numeric order, use sort with an extra expression just before the list to be sorted:

@keys = sort { $a <=> $b }  keys %hash;

What does that bit in the middle with the <=> operator do? What are $a and $b for? Up until now, I asked you to just learn that line by heart; here's where I'll explain what all that means.

The extra bit between curly brackets in the sort determines how the list is to be sorted, by describing what happens when one element is greater than, less than, or equal to another. Given two arguments ($a and $b), the expression inside the block should return an integer less than 0 (if the first argument is less than the second), an integer greater than 0 (if the first argument is greater), or 0 (if the two arguments are equal).

Perl, conveniently, has two operators that do just this, making it easy for you to write simple sort routines. Why two operators? For the same reason there are two sets of equality and relational operators: one for strings (cmp), and one for numbers (<=>).

The cmp operator works on strings, comparing two arguments and returning -1, 0, or 1 depending on whether the first operand is less than, equal to, or greater than the second. You could write cmp the long way something like this:

$result = '';
if ($a lt $b ) { $result = -1; }
elsif ($a gt $b { $result = 1; }
else { $result = 0; }
					

The <=> operator, sometimes called the spaceship operator for its appearance, does exactly the same comparison, only for numbers.

Which brings us to the $a and $b part of the sort routine. The $a and $b variables are temporary to the sort (you don't have to declare them, they go away when the sort's done), and contain elements in the list you're sorting. If you were going to write your own sort routine inside the block, you would use $a and $b to refer to the two elements that need to be compared each time.

Note

Because $a and $b are special to the sort routine, and refer to two elements in the list, be careful about using variables named $a and $b in your scripts, or of changing the values of $a and $b inside your sort routine. Weird and unexpected results can occur.


The default sort routine uses the cmp operator to compare values (which is why it sorts in ASCII order). Using { $a <=> $b } compares the values with a numeric comparison, which sorts those values in numeric order.

By default these sort routines have sorted lists in ascending order. To sort in the reverse order, simply reverse $a and $b:

@keys = sort { $b <=> $a }  keys %hash;

You can print a hash, sorted by keys, using a sort routine and a foreach loop. If you want to do the same thing with the values in the hash, however, things can get a little complicated. If all you need are the values, you can just use the values function to get a list of those values, and then sort it. By doing that you lose access to the original keys and there's no way to associate a raw value back to its key. You can, however, sort the keys in value order, and then print out both the key and its value, like this:

foreach $key (sort {$things{$a}  cmp $things{$b} }  keys %things) {
   print "$key, $things{$key} 
";
}

Here, the sort routine, instead of using raw keys for the values of $a and $b, sorts the values associated with the keys ($things{$a} and $things{$b}) instead. The resulting list, which we iterate over using foreach, is a list of the keys in the hash sorted by value.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset