Here's a function that can sort a matrix in all possible ways.
the following Python version i wrote in 2006, but was incorrect.
# -*- coding: utf-8 -*- # python # WARNING: THE CODE IS INCORRECT. # sort_matrix( matrix, [[n1, s1, d1], [n2, s2, d2], [n3, s3, d3], …]) returns a sorted matrix by n1 th column, if tie, then by n2 th column … and so on. # The first argument is a list, whose elements are lists of equal lengths. # s1, s2, s3… are booleans. If True, then the corresponding column are interpreted as a string and the ordering is lexicographical. # d1, d2, d3… are booleans. If True, the sort for the corresponding column are ascending. # Example:. # myMatrix = # [ # [3, 99, 'a'], # [2, 77, 'a'], # [1, 77, 'a'] # ]; # sort_matrix(myMatrix,[[3,True,True],[2,False,True]]) # This means sort by 3th column, regarding it as strings, and in ascending order. If tie, sort by 2th column, regarding it as number, in ascending order. It returns: # [[2,77,'a'], # [1,77,'a'], # [3,99,'a']] def sort_matrix(matrix, directives): result=matrix for dir in directives: if dir[1]: # consider as string if dir[2]: # ascending result.sort(lambda x,y: cmp( str(x[dir[0]-1]), str(y[dir[0]-1])) ) else: # descending result.sort(lambda x,y: cmp( str(x[dir[0]-1]), str(y[dir[0]-1])), None, True) else: # consider as number if dir[2]: # ascending result.sort(lambda x,y: cmp(float(x[dir[0]-1]), float(y[dir[0]-1])) ) else: # decending result.sort(lambda x,y: cmp(float(x[dir[0]-1]), float(y[dir[0]-1])), None, True ) return result
This Perl version i wrote in 1999, and was put in production use in a ecommerce server.
# -*- coding: utf-8 -*- # perl =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]; };blog comments powered by Disqus