use 5.012; use warnings; use constant { # Common collation sequences ALPHA => sub { my ($a, $b) = @_; $a cmp $b }, NUMERIC => sub { my ($a, $b) = @_; $a <=> $b }, # Sort orders ASC => +1, DSC => -1 }; # Multicolumn sort function. # Params: # $columns = Arrayref of sort column definitions in priority order. # Each column definition is a hashref with the keys # index => Column index in the data rows # collate => Binary subref defining collation order # order => ASC for ascending or DSC for descending order # $data = Arrayref of data rows # Returns: # Arrayref of sorted data rows sub multisort { my ($columns, $data) = @_; [sort { for my $column (@$columns) { my $d = $column->{order} * $column->{collate}->($a->[$column->{index}], $b->[$column->{index}]); return $d unless $d == 0; } } @$data]; } # Runnable example: my @data = ( ['aaron', 'zander', 20], ['hannes', 'zander', 20], ['aaron', 'suppe', 10], ); my @columns = ( {index => 2, collate => NUMERIC, order => ASC}, {index => 1, collate => ALPHA, order => ASC}, {index => 0, collate => ALPHA, order => ASC}, ); use Data::Dumper; print Dumper multisort(\@columns, \@data);