以编程方式更改Perl中的排序顺序($ a <=> $ b)

时间:2019-05-31 09:04:20

标签: perl

我想让用户可以更改数据结构中的排序顺序(asc / desc)。据我所知,这是通过更改代码中$a$b的顺序来完成的,但是我想以编程方式更改它以避免重复的代码。

我举了一个可行的例子:

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'};
    }   
}

提供任何参数将更改sorting_direction。我可以在没有 if 条件的情况下执行此操作吗?

3 个答案:

答案 0 :(得分:8)

由于<=>的值为-1、0或1,您可以乘以-1以获得相反的排序顺序。

因此,如果您的$ sorting_direction是1或-1,请使用

$sorting_direction * ( $$data{$a}{'size'} <=> $$data{$b}{'size'} )

答案 1 :(得分:6)

一个通用的解决方案是使用不同的比较函数。

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);

您还可以使用其他排序功能,例如在使用出色的Sort::Key模块时。

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) );

答案 2 :(得分:0)

尽管它总是很慢,因为这是一个额外的操作,但是如果性能与代码整洁度无关紧要,则可以选择reverse,而选择相反的排序方向。请注意,在对相等元素进行排序的情况下,这会稍有不同,因为Perl中的sort通常是稳定的(相等元素保持与原来相同的顺序)。

my @sorted = sort { $$data{$a}{'size'} <=> $$data{$b}{'size'} } keys %{$data};
@sorted = reverse @sorted if $reverse;