Perl Sorting ActiveWare Perl5.00502 for NT Phillip Thorne August 1998 1. Beware of Perl default sorts! ## Original unsorted list. @x = (1, 2, 1, 10, 20, 3, 1, 2, 3, 2, 3); ## The default sort is stringwise. @y1 = sort @x; @y1 = (1, 1, 1, 10, 2, 2, 2, 20, 3, 3, 3); ## Explicitly same as the default sort. @y2 = sort {$a cmp $b} @x; @y2 = (1, 1, 1, 10, 2, 2, 2, 20, 3, 3, 3); ## Sort numerically. @y3 = sort {@a <=> $b} @x; @y3 = (1, 1, 1, 2, 2, 2, 3, 3, 3, 10, 20); The default Perl sorting (collating) order is stringwise ASCII. You have to insert your own comparator to sort in numeric order. 2. Beware also the invocation syntax with a custom comparator function! sort(&byX, @x); ## Compiles, wrong, prepends empty value sort &byX, @x ; ## Compiles, as above sort byX, @x ; ## Syntax err, "no comma allowed after subroutine name" sort &byX @x ; ## Syntax err, "array found where operator expected" sort byX @x ; ## Compiles, correct, no extras Only the last invocation compiles and produces the correct output. The others are syntax errors, or prepend a "0" to the head of the list (or an "[]" if you're sorting a list-of-refs-to-lists) and sort by the default ASCII order. 3. And when sorting key-value lists with nonunique keys! When two keys in a list are equivalent, one invocation of the sort() routine may order the values one way, and a second invocation in another. Be safe and use a fallback comparator as in: ($values{$a} cmp $values{$b}) || ($a cmp $b); 4. And when performing cascaded sorts! Don't try to sort the list with one comparator, and then with another in a separate invocation. Do it all in a single comparator; see above. 5. And when sorting complex structures! ## List of refs to anonymous lists. @p = ([6,1,1], [6,2,17], [10,1,28], [12,3,64]); ## Sort by second value in each sub-list. @q = sort { ${@$a}[1] <=> ${@$b}[2] } @p; @q = ([6,1,1], [10,1,28], [6,2,17], [12,3,64]); Note the dereferencing syntax: $a is the global passed to sort(), and is a reference to a list. @$a is the reference dereferenced as an array. $a[1] would be the index lookup for a normal list. $@$a[1] is a syntax error. ${@$a}[1] is syntactically correct. Remember, dereferences aren't really operators, or you could use parens to change the order. Instead, you need to disambiguate using curlies. Also, key and index lookups have the lowest precedence. Also remember, the anonymous list constructor syntax [1, 2, 3] automatically returns a reference; you don't need to prepend-backslash: \[1, 2, 3]. 6. Comparator syntaxes Inline Subroutine