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 $b
in 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?
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'} )
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) );
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With