use 5.012; use warnings; my %collations = ( ALPHA => sub { my ($a, $b) = @_; $a cmp $b }, NUMERIC => sub { my ($a, $b) = @_; $a <=> $b }, ); my %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 => 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 $order = $orders{$column->{order}} or die 'illegal sort order ' . $column->{order}; my $collate = $collations{$column->{collate}} or die 'illegal collation sequence ' . $column->{collate}; my $index = $column->{index}; my $d = $order * $collate->($a->[$index], $b->[$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);