奇怪的排序行为

时间:2010-07-09 14:00:29

标签: perl sorting

我有这段剧本:

#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;

my @arr = (
    {
        name  => 'foo',
        value => 123,
    },
    {
        name  => 'bar',
        value => 'nan',
    },
    {
        name  => 'foobar',
        value => 456,
    },
);

@arr = sort {$a->{value} <=> $b->{value} } @arr;

print Dumper(\@arr);

我在Windows XP / Strawberry Perl 5.10.1

下没有任何问题

为i386-linux-thread-multi构建的Linux 2.6.12-1 i386 / Perl v5.8.5,

但是在针对x86_64-linux-thread-multi构建的Linux 2.6.18-53 / Perl v5.8.8下,我收到了错误消息:

Sort subroutine didn't return a numeric value at testsort.pl line 21.

出了什么问题,我该如何解决?

2 个答案:

答案 0 :(得分:6)

在某些版本中,对于<=>比较,'nan'被强制为0,排序成功。在其他版本中,nan被视为“非数字”,<=>的返回值未定义。

为了获得最大的可移植性,请测试一个值是否为好的数字:

(来自How do I create or test for NaN or infinity in Perl?isnan子程序):

sub isnan { ! defined( $_[0] <=> 9**9**9 ) }

@arr = sort { isnan($a->{value}) ? 0 : $a->{value}
                         <=>  
              isnan($b->{value}) ? 0 : $b->{value} }  @arr;

答案 1 :(得分:4)

2解决方案

  1. mobrule的解决方案:

    sub isnan { ! defined( $_[0] <=> 9**9**9 ) }
    @arr = sort { isnan($a->{value}) ? 0 : $a->{value}
                                  <=>  
                  isnan($b->{value}) ? 0 : $b->{value} }  @arr;
    
  2. Perldoc的解决方案:

    @result = sort { $a <=> $b } grep { $_ == $_ } @input;
    

    1. 提供NaN 0值,该值应将其推送到列表顶部。
    2. 利用NaN != NaN来消除输入列表中的任何NaN

    3. 正如mobrule所述,这是由于构建之间NaN的比较造成的。