Perl: Sort Matrix

By Xah Lee. Date: . Last updated: .

Here's a function that can sort a matrix in all possible ways.

This Perl version i wrote in 1999, and was used in production of a ecommerce server.

```=pod

sort_matrix( \$matrix, [[\$n1, \$stringQ, \$directionQ], [\$n2, \$stringQ,
\$directionQ], …]) sorts a matrix by \$n1 th column then \$n2 th…and
so on.

\$matrix must be a reference to references of arrays, having the form
[[\$e1, \$e2,…], […], …].  \$stringQ is a boolean indicating
whether to treat corresponding columns as a strings instead of as
number in the sorting process. True means string. \$directionQ is a
boolean indicating ascending sort or not for the corresponding
column. In the column spec \$n1 \$n2 …, index counting starts at 0.

Example:

my \$ref_matrix =
[
[3, 99, 'a'],
[2, 77, 'a'],
[1, 77, 'a']
];

sort_matrix( \$ref_matrix,  [ [2,1,1], [1,0,1] ]);
# this means sort by third column, regarding it as strings,
# and in ascending order. If tie, sort by second column,
# regarding it as number, in ascending order.

# returns [[2,77,'a'],[1,77,'a'],[3,99,'a']];

=cut

sub sort_matrix(\$\$) {
my \$ref_matrix = \$_[0];
my @indexMatrix = @{\$_[1]};

my @indexes = map {\$_->[0]} @indexMatrix;
my @operators = map {\$_->[1] ? ' cmp ' : ' <=> '} @indexMatrix;
my @directions = map {\$_->[2]} @indexMatrix;

my \$body_code = '';
my @body_array;
for (my \$i = 0; \$i <= \$#indexes; \$i++) {
if (\$directions[\$i]) {
push(@body_array, "(\\$a->[\$i]" . \$operators[\$i]  . "\\$b->[\$i])");
} else {
push(@body_array, "(\\$b->[\$i]" . \$operators[\$i]  . "\\$a->[\$i])");
};
};
\$body_code = join( ' or ', @body_array);

my \$array_code = '(map { [' . join(q(, ), map {"\\$_->[\$_]"} @indexes) . ', \$_]} @\$ref_matrix)';

my \$code = "map {\\$_->[-1]} (sort { \$body_code} \$array_code)";
my @result = eval \$code;
return [@result];
};```