Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically change sorting order in Perl

I'd like to give the user the possibility to change the sorting order (asc / desc) in a data structure. As far as I know, this is done changing the order of $a and $bin the code, but I'd like to programmatically change this to avoid redundant code.

I made a working example:

use 5.018;
use warnings;

# Supply any argument to change sorting order
my $sorting_direction = $ARGV[0];

my $data = {
          'item1' => {
                         'min'  => 4,
                         'size' => 825,
                         'max'  => 256,
                       },
          'item2' => {
                         'min'  => 4,
                         'size' => 130,
                         'max'  => 65,
                       },
        };


if (defined $sorting_direction) {
    foreach my $item (sort { $$data{$a}{'size'} <=> $$data{$b}{'size'} } keys %{$data} ) {
        say "$item\t", $$data{$item}{'size'};
    }
} else {
    foreach my $item (sort { $$data{$b}{'size'} <=> $$data{$a}{'size'} } keys %{$data} ) {
        say "$item\t", $$data{$item}{'size'};
    }   
}

Giving any parameter will change the sorting_direction. Can I do this without the if conditional?

like image 373
Andrea T. Avatar asked Dec 04 '22 18:12

Andrea T.


2 Answers

As <=> has a value of -1, 0 or 1, you can multiply with -1 to get the opposite sorting order.

So if your $sorting_direction is 1 or -1 use

$sorting_direction * ( $$data{$a}{'size'} <=> $$data{$b}{'size'} )
like image 193
Skeeve Avatar answered Jan 14 '23 07:01

Skeeve


A generic solution is to use different compare functions.

my %sorters = (
   by_size_asc  => sub { $data->{$a}{size} <=> $data->{$b}{size} },
   by_size_desc => sub { $data->{$b}{size} <=> $data->{$a}{size} },
   # ...
);

@ARGV
   or die("usage\n");

my $sorter = $sorters{$ARGV[0]}
   or die("Invalid sort function \"$ARGV[0]\".\n");

my @sorted_keys = sort $sorter keys(%$data);

You could also use different sort functions, such as when using the great Sort::Key module.

use Sort::Key qw( ikeysort rikeysort );

my %sorters = (
   by_size_asc  => sub { ikeysort  { $data->{$_}{size} } @_ },
   by_size_desc => sub { rikeysort { $data->{$_}{size} } @_ },
   # ...
);

@ARGV
   or die("usage\n");

my $sorter = $sorters{$ARGV[0]}
   or die("Invalid sort function \"$ARGV[0]\".\n");

my @sorted_keys = $sorter->( keys(%$data) );
like image 22
ikegami Avatar answered Jan 14 '23 08:01

ikegami