2010-07-09 3 views
7

J'ai ce morceau de script:Comportement étrange de sorte

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

Je n'ai pas de problèmes sous Windows XP/Strawberry Perl 5.10.1

soit Linux 2.6.12-1 i386/Perl v5.8.5 construit pour i386-linux-thread-multi,

mais sous Linux 2.6.18-53/Perl v5.8.8 construit pour x86_64-linux-thread-multi, je reçu le message d'erreur:

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

Qu'est-ce qui ne va pas et comment puis-je le réparer?

+0

Est-ce que la même chose se produit si vous le simplifiez comme ceci? @arr = sort {$ a <=> $ b} (123, 'nan', 456); – wdebeaum

+0

@wdebeaum: pas d'erreur dans un liner mais ne fait rien sous x86_64 alors que c'est OK sous win XP et i386 – Toto

Répondre

6

Dans certaines versions, 'nan' est forcé au nombre 0 pour une comparaison <=> et le tri réussit. Dans les autres versions, nan est traitée comme "not a number" et la valeur de retour de <=> est indéfinie.

Pour une portabilité maximale, tester une valeur pour que ce soit un bon nombre de pas:

(isnan sous-programme de 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

Cela fonctionne. J'ai entouré ternaire par parenthèse. – Toto

4

2 Solutions

  1. mobrule La solution:

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

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

  1. donne votre NaN une valeur 0, ce qui devrait le pousser vers le haut de la liste.
  2. Prend avantage que NaN != NaN, pour éliminer NaN s de la liste d'entrée.

Comme mobrule indiqué, cela est causé par la comparaison des NaN entre builds.