2

我有一些正在运行的代码,但会发出很多警告。

    foreach my $item ( sort {$item_rank{$a} <=> $item_rank{$b}} @items{
        ...
    }

我的问题是,并非每个项目都有排名,因此我的输出充满了警告。我想让没有排名的项目最后。我正在考虑将代码更改为如下:

    foreach my $item ( sort {
                              $item_rank{$a} = 99999 if(!exist $item_rank{$a});
                              $item_rank{$b} = 99999 if(!exist $item_rank{$b});
                              $item_rank{$a} <=> $item_rank{$b}} @items{
        ...
    }

我的问题是,是否有一个特定的值可以设置为而不是 99999,尽管在当前设置中我永远不会达到 99999,但我希望我的代码更健壮。

谢谢

4

2 回答 2

4

您可以通过以下两种方式之一进行操作:

  • 如果您定义了最大上限,则默认为它(为了简化代码,我假设 0 不是有效等级)

    $max_ceiling = 99999;
    sort { ($item_rank{$a} || $max_ceiling)
       <=> ($item_rank{$b} || $max_ceiling) } @items
    

    或者,为了避免分配给哈希:

    # Ideally, %item_rank should be passed as a parameter but meh.
    sub rank4comp { exist $item_rank{$_[0]} ? $item_rank{$_[0]} : 999999; }
    sort { rank4comp($a) <=> rank4comp($b) } @items;
    
  • 更好的是,在您的表达式中显式检查 undef(请记住,排序的代码块可以是任何表达式,它返回负数、0 或正数 ala “ <=>”:

    sort { defined $item_rank{$a}
         ? defined $item_rank{$b}
         ? $item_rank{$a} <=> $item_rank{$b} : 1 : -1 } @items;
    
于 2012-06-06T15:01:56.253 回答
3

由于您对未排名记录的标准有明确的定义,因此您不妨将两组分开:

my @unranked = grep ! defined($item_rank{$_}), keys %item_rank;
my @ranked   = grep   defined($item_rank{$_}), keys %item_rank;

然后你可以像往常一样排序,甚至可以将两个数组包含在同一个 for 循环中:

for my $item (sort ( { $item_rank{$a} <=> $item_rank{$b} } @ranked), @unranked) {
    print "$item => ", $item_rank{$item} // "N/A", "\n";
}

这将自动将所有未排名的项目放在最后。

请注意,您需要在参数周围加上括号,sort以避免元素@unranked成为sort. 我使用defined-or运算符//检查打印语句中的未定义值。

您甚至可以将排序移至grep语句:

my @unranked = grep ! defined($item_rank{$_}), keys %item_rank;
my @ranked   = sort { $item_rank{$a} <=> $item_rank{$b} }
                   grep defined($item_rank{$_}), keys %item_rank;

for my $item (@ranked, @unranked) { 
...
于 2012-06-06T16:37:39.423 回答