2010-07-09 27 views
7

ho questo pezzo di script:strano comportamento di tipo

#!/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); 

Non ho alcun problema sotto Windows XP/Strawberry Perl 5.10.1

sia Linux 2.6.12-1 i386/Perl v5.8.5 costruita per i386-linux-thread-multi,

ma sotto Linux 2.6.18-53/Perl v5.8.8 costruito per x86_64-linux-thread-multi, ho ricevuto il messaggio di errore:

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

Cosa non va e come posso risolverlo?

+0

La stessa cosa accade se lo si semplifica in questo modo? @arr = sort {$ a <=> $ b} (123, 'nan', 456); – wdebeaum

+0

@wdebeaum: nessun errore in un liner ma non ordina nulla sotto x86_64 mentre è ok sotto win XP e i386 – Toto

risposta

6

In alcune build, 'nan' è forzato al numero 0 per un confronto <=> e l'ordinamento ha esito positivo. In altre build, nan viene considerato come "non un numero" e il valore restituito da <=> non è definito.

Per la massima portabilità, testare un valore per se è un buon numero di non:

(isnan subroutine da How do I create or test for NaN or infinity in Perl?):

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

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

Funziona. Ho circondato il ternario per parentesi. – Toto

4

2 Soluzioni

  1. mobrule La soluzione:

    sub isnan { ! defined($_[0] <=> 9**9**9) } 
    @arr = sort { isnan($a->{value}) ? 0 : $a->{value} 
               <=> 
           isnan($b->{value}) ? 0 : $b->{value} } @arr; 
    
  2. s' Perldoc soluzione:

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

  1. Dà il tuo NaN un valore 0, che dovrebbe spingerlo in cima alla lista.
  2. Approfitta di NaN != NaN per eliminare qualsiasi NaN dall'elenco di input.

Come mobrule detto, questo è causato dal confronto di NaN tra generazioni.