probleme avec sort [resolu]

probleme avec sort [resolu] - Perl - Programmation

Marsh Posté le 15-08-2005 à 22:24:35    

Bonjour,
j'ai un tableau de chaines de caracteres, chaque chaine se terminant par deux digits en hexadecimal. Je voudrais trier le tableau selon ces valeurs hexa... j'ai essaye pleins de trucs sans succes. J'en suis la:
 

sub test($)
{
    s/^.*([0-9a-zA-Z]{2})$/$1/;
    hex;
}
 
 
@opcodes = sort {test($a) <=> test($b)} @entries;
 
foreach (@opcodes)
{
    print "$_\n";
}


j'ai des warnings a l'execution et le tableau n'est pas trie finalement.

Use of uninitialized value in hex [...]


Use of uninitialized value in substitution [...]


Je me dis que $a et $b sont indefinis au moment ou ils sont passes en parametres a test, mais dans ce cas je dois pas avoir compris comment marche sort.
Sinon j'ai essaye sans passer par une fonction intermediaire:

@opcodes = sort {hex($a =~ s/^.*([0-9a-zA-Z]{2})$/$1/) <=> hex($b =~ s/^.*([0-9a-zA-Z]{2})$/$1/)} @entries;


Plus de warnings, mais a l'affichage j'ai juste la valeur prise par $1, et c'est toujours pas trie.
Quelqu'un pourrait m'expliquer ou me guider vers la solution?
merci d'avance :)


Message édité par Shabang le 16-08-2005 à 11:07:36
Reply

Marsh Posté le 15-08-2005 à 22:24:35   

Reply

Marsh Posté le 15-08-2005 à 23:47:02    

finalement ca marche en definissant ma fonction de sort comme ca:


@opcodes = sort {
    my $h1 = $a;
    my $h2 = $b;
    $h1 =~ s/.*([0-9a-fA-F]{2})$/$1/;
    $h2 =~ s/.*([0-9a-fA-F]{2})$/$1/;
    hex($h1) <=> hex($h2)
    } @entries;


mais je trouve ca plutot crade... il y a plus efficace?


Message édité par Shabang le 15-08-2005 à 23:51:09
Reply

Marsh Posté le 16-08-2005 à 08:40:47    

oui voila, ta sub de sort doit etre definie entierement pour $a et $b. mais tu peu tres bien mettre ca dans une fonction plutot qu'un bloque:
 

Code :
  1. sub _sort_sub {
  2.     my $h1 = $a;
  3.     my $h2 = $b;
  4.     $h1 =~ s/.*([0-9a-fA-F]{2})$/$1/;
  5.     $h2 =~ s/.*([0-9a-fA-F]{2})$/$1/;
  6.     hex($h1) <=> hex($h2)
  7. }
  8. @opcades = sort _sort_sub @entries;


 
ensuite pour ta sub ca me semble bizarre qu'elle marche deja! Tu a de la chance que le moteur regexp de Perl parte de la fin (qui est ici mieux definie que le debut) pour matcher sinon ca ne marcherait pas car le .* consommerait tout (d'ailleurs il el fait peut etre!)
 
je te propose plutot cette sub la:

Code :
  1. sub _sort_sub {
  2.     hex(substr($a, -2)) <=> hex(substr($b, -2))
  3. }


 
ou mieux (plus rapide) :

Code :
  1. sub _sort_sub {
  2.     lc(substr($a, -2)) cmp lc(substr($b, -2))
  3. }


 
et si tu es certain que des caracteres hexa serton soit entirement en majuscules soit entierement en minuscules tu peux encore te passer du lc() et gagner un peu plus en vitesse.
 
Ensuite si ta liste est vraiment enorme il y a d'autres moeyn d'optimiser (en se passant totalement de sub de tri) mais c'est plus compliqué


Message édité par pospos le 16-08-2005 à 08:41:27
Reply

Marsh Posté le 16-08-2005 à 10:03:42    

pospos a écrit :


je te propose plutot cette sub la:

Code :
  1. sub _sort_sub {
  2.     hex(substr($a, -2)) <=> hex(substr($b, -2))
  3. }


 
ou mieux (plus rapide) :

Code :
  1. sub _sort_sub {
  2.     lc(substr($a, -2)) cmp lc(substr($b, -2))
  3. }


 
et si tu es certain que des caracteres hexa serton soit entirement en majuscules soit entierement en minuscules tu peux encore te passer du lc() et gagner un peu plus en vitesse.


Oui c'est vrai, c'est beaucoup plus simple que de matcher ca avec une regexp. Super, merci =)
 

Citation :

Ensuite si ta liste est vraiment enorme il y a d'autres moeyn d'optimiser (en se passant totalement de sub de tri) mais c'est plus compliqué


Justement dans la doc de sort, j'ai vu qu'il y avait moyen de passer par des tableaux anonymes pour optimiser les clefs de tris... ca m'a l'air plus complexe et de toutes facons ma liste est peu gourmande (256 chaines de caracteres plutot courtes), donc j'ai laissé tombé. Je me pencherai un peu plus dessus plus tard par curiosité :)
Merci infiniment en tout cas. Ca m'embeterai de recréer un topic juste pour ca, mais est-ce qu'il existe une fonction qui permet de retourner l'index de la premiere occurence d'un élément dans une liste, si celui-ci est trouvé? Je pensais a grep, mais c'est le nombre d'éléments qui est retourné en contexte scalaire donc ca m'interresse moyen.
Sinon tant pis, je ferais le parcours de la liste a la main avec un indice:

       for ($i = 0; $i < @addr_modes; $i++)
        {
            last if ("$addr_mode" eq "$addr_modes[$i]" );
        }
        push(@addr_modes, $addr_mode) if ($i == @addr_modes);


Message édité par Shabang le 16-08-2005 à 10:22:53
Reply

Marsh Posté le 16-08-2005 à 10:51:43    

il vaut mieux recrer un topic pour chaque question: ca facilite la recherche par la suite (on est sur un forum, pas sur un chat)
 
Pour ta question tu peu utiliser le module List::Util
il fait partie du CORE depuis Perl 5.8, donc normalement tu dois l'avoir
 

Code :
  1. use List::Util "first";
  2. my $val = first {$_ > $value} @liste


 
 
EDIT: en fait ca retounr l'element lui meme, alors que tyoi tuveux l'indice...
Dans ce cas tu n'a d'autre choix que le parcourt manuel, mais tu peux au moins de cacher dans une fonction
 
dans ce cas je te conseil plutot ca:

Code :
  1. sub list_index {
  2.     my ($value, $list_ref) = @_;
  3.     my $i=0;
  4.     for (@$list_ref) {
  5.         return $i if $_ eq $value;
  6.         ++$i;
  7.     }
  8.     return -1; # element absent
  9. }


Message édité par pospos le 16-08-2005 à 10:55:58
Reply

Marsh Posté le 16-08-2005 à 11:06:39    

vu, merci.

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed