【问题标题】:Programmatically change sorting order in Perl以编程方式更改 Perl 中的排序顺序
【发布时间】:2019-10-16 22:01:11
【问题描述】:

我想让用户可以更改数据结构中的排序顺序(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 条件的情况下执行此操作吗?

【问题讨论】:

  • 我对 Skeeve 的回答(因为它的简单性和有助于更好地理解排序机制)和 ikegami 的回答(可能更优雅,也指向一个不错的模块)都印象深刻。如果可以的话,我两个都接受!

标签: arrays perl sorting


【解决方案1】:

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

所以如果你的 $sorting_direction 是 1 或 -1 使用

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • nsort_byrev_nsort_by from List::UtilsBy 也可以类似于那些 Sort::Key 函数使用。
    • 谢谢!我实现了第一个案例,因为它还解决了第二个需求:如果值不是数字,则可以在 &lt;=&gt;cmp 之间进行选择。
    • @Grinnz,我想,但该模块只提供了 Sort::Key 功能的一小部分。
    【解决方案3】:

    虽然它总是慢得慢,因为它是一个完整的额外操作,如果性能与代码清洁度的关注点不多,你可以在选择相反的排序方向时reverse列表。请注意,这在对相等元素进行排序的情况下会略有不同,因为 Perl 中的排序通常是稳定的(相等的元素保持与它们最初的顺序相同)。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-06
      • 1970-01-01
      • 2014-03-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多