next up previous contents
Next: sleep Up: A Few Perl Functions Previous: substr   Contents


sort

The default behaviour of the sort routine is to accept as an argument a list or array of values, and to return a lexigraphically (alphabetically) sorted list of those values. While this is useful for strings, it produces undesired results when used on an array of numbers:
@nums = (1,20,10,100,19,32,4);       
print join(' ',sort(@nums));  # prints 1 10 100 19 20 32 4
To accomodate this and many other cases where a lexigraphic sort is not appropriate, you can pass perl a block of statements describing how perl should compare pairs of objects in order to properly sort your data. This block of statements must refer to the two values being compared as $a and $b, and must return the value -1 when $a is less than $b, 0 when $a equals $b, and 1 when $a is greater than $b. Note that this is exactly the behavior of the builtin cmp and <=> comparison operators (Section 3.4). Thus, the solution to the problem of sorting numbers is simple:
@nums = (1,20,10,100,19,32,4);       
print join(' ',sort({$a <=> $b} @nums));  # prints 1 4 10 19 20 32 100
The expression provided must be enclosed in curly braces. Also note that, like a filehandle in a print statement (Section [*]), there is no comma after the expression. (As an alternative, a function can be passed to sort, but it still must compare two variables called $a and $b.)

While this method of sorting may seem unusual, it offers a great deal of flexibility. For example, if we wish to perform a sort of a list of strings, ignoring their case, we can use the lc function to convert the strings to lower case before comparison.

@names = ("andy","Alice","bob","Brad");   
print join(' ',sort(@names));   #prints Alice Brad andy bob
print join(' ',sort({lc($a) cmp lc($b)} @names)); 
                                #prints Alice andy bob Brad

More complex sorting can also be accomplished. Suppose we have a hash named %accounts, whose keys represent the names of clients, and whose values represent the corresponding client's account balance. We would like to sort the keys of %accounts so that the client with the largest balance is first, the next largest second, and so on. Reversing the order of the sort is easy; simply reverse the roles of $a and $b. Since we want to sort the keys by the value of %accounts corresponding to the keys, we simply use the value of the hash in our sorting expression:

@skeys = sort({$accounts{$b} <=> $accounts{$a}} keys(%accounts));


next up previous contents
Next: sleep Up: A Few Perl Functions Previous: substr   Contents
Phil Spector 2002-10-18