IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Perl Discussion :

tri complex ?


Sujet :

Langage Perl

  1. #1
    Membre actif Avatar de CKLN00
    Homme Profil pro
    Bioinformaticien Java/Perl
    Inscrit en
    Avril 2008
    Messages
    210
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Vienne (Poitou Charente)

    Informations professionnelles :
    Activité : Bioinformaticien Java/Perl
    Secteur : Santé

    Informations forums :
    Inscription : Avril 2008
    Messages : 210
    Points : 263
    Points
    263
    Par défaut tri complex ?
    Salut ,
    alors je cherche à faire un tri sur un tableau
    les éléments du tableau sont du type : 123,55*
    soit /\d+ \d+[X><*]/ sous forme d'expression réguliere
    et en fait j'aimerais trier ma liste comme suit : selon le chiffre qui vien avant la virgule et en cas d'égalité selon le chiffre qui suit la virgule c a d si j'ai :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    my @list = ('19,12*','1,15X','100,1<','1,8>','19,20X','100,0*') ;
    # j'aimerais avoir à la fin :
    @list_trie = ('1,8>','1,15X','19,12*','19,20X','100,0*','100,1<')
    mais je n'ai pas trouver quelles instruction mettre dans le bloque du sort
    CKL
    N°°b forever
    --
    may the be with you

  2. #2
    Membre émérite
    Avatar de Jasmine80
    Femme Profil pro
    Bioinformaticienne
    Inscrit en
    Octobre 2006
    Messages
    3 157
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 44
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Bioinformaticienne
    Secteur : Santé

    Informations forums :
    Inscription : Octobre 2006
    Messages : 3 157
    Points : 2 673
    Points
    2 673
    Par défaut
    A ta place je créerais un tableau dont la clé serait composée du chiffre décimal correspondant à ton entier et ta fraction et je placerais la valeur entière de ta donnée en valeur


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $hash{19.12} = '19,12*';
    $hash{1.15} = '1,15X' ;
    $hash{100.1} = '100,1<';
    $hash{1.8} =  '1,8>';
    Tu remplis ta hash via une expreg et ensuite tu fais un (sort {$a<=>$b] keys %hash ) et le tour est joué !!!


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    #!/bin/perll
     
    use strict;
    use warnings;
     
    my @list = ('19,12*','1,15X','100,1<','1,8>','19,20X','100,0*') ;
     
    my %hash;
     
    foreach my $val (@list ){
    		my ($ent, $dec) = ( $val =~ /(\d+),(\d+)\D/);
    		$hash{$ent.'.'.$dec} = $val;
    }
     
    my @sort;
     
    foreach my $x (sort {$a<=>$b} keys %hash){
    		push(@sort, $hash{$x});
    }
     
    map{print $_."\n";} @sort;
    -- Jasmine --

  3. #3
    Membre actif Avatar de CKLN00
    Homme Profil pro
    Bioinformaticien Java/Perl
    Inscrit en
    Avril 2008
    Messages
    210
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Vienne (Poitou Charente)

    Informations professionnelles :
    Activité : Bioinformaticien Java/Perl
    Secteur : Santé

    Informations forums :
    Inscription : Avril 2008
    Messages : 210
    Points : 263
    Points
    263
    Par défaut
    j'avais pensé à cette méthode sauf que 19.10 seras AVANT 19.9 alors que justement je ne veut pas !
    CKL
    N°°b forever
    --
    may the be with you

  4. #4
    Membre émérite
    Avatar de Jasmine80
    Femme Profil pro
    Bioinformaticienne
    Inscrit en
    Octobre 2006
    Messages
    3 157
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 44
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Bioinformaticienne
    Secteur : Santé

    Informations forums :
    Inscription : Octobre 2006
    Messages : 3 157
    Points : 2 673
    Points
    2 673
    Par défaut
    http://www.sysarch.com/Perl/sort_paper.html


    Multi-subkey sorts

    In some cases you need to sort records by a primary subkey, then for all the records with the same primary subkey value, you need to sort by a secondary subkey. One horribly inefficient way to do this is to sort first by the primary subkey, then get all the records with a given subkey and sort them by the secondary subkey. The standard method is to do a multi-key sort. This entails extracting a subkey for each field, and comparing paired subkeys in priority order. So if two records with the same primary subkey are compared, they will actually be compared based on the secondary subkey. Sorting on more than two subkeys is done by extending the logic.

    Perl has a very nice feature which makes multi-key sorts easy to write. The || (short-circuit or) operator returns the actual value of the first logically true operand it sees. So if you use || to concatenate a set of key comparisons, the first comparison is the primary subkey. If a pair of primary subkeys compare equal, the sortsub´s return value will be the result of the secondary subkey comparison.
    -- Jasmine --

  5. #5
    Membre émérite
    Avatar de Jasmine80
    Femme Profil pro
    Bioinformaticienne
    Inscrit en
    Octobre 2006
    Messages
    3 157
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 44
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Bioinformaticienne
    Secteur : Santé

    Informations forums :
    Inscription : Octobre 2006
    Messages : 3 157
    Points : 2 673
    Points
    2 673
    Par défaut
    J'ai mis le temps à comprendre le fonctionnement mais cela fait ce que tu veux.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    #!/bin/perll
     
    use strict;
    use warnings;
     
    my @in = ('19,12*', '19,9U', '1,15X','100,1<','1,8>','19,20X','100,0*') ;
     
    my @out = sort {
     
             $a =~ /(\d+,\d+)\D+/;
             $b =~ /(\d+,\d+)\D+/;
     
             (split ',', $a)[0] <=> (split ',', $b)[0]  ||
             (split '\D', $a)[1] <=> (split '\D', $b)[1] 
    } @in;
     
     
     
     
     
    map{print $_."\n";} @out;
    Je ne sais pas pourquoi mais dans $a =~ /(\d+,\d+)\D+/; , $a récupère quand même les lettres et donc lors du second tri, Perl n'est pas content. J'évite les messages d'erreurs en effectuant le second split sur '\D' au lieu de ',' afin de me débarasser des lettres excédentaires.

    Voila, en attendant de trouver mieux, tu peux utiliser cette façon de procéder.
    -- Jasmine --

  6. #6
    Membre actif Avatar de CKLN00
    Homme Profil pro
    Bioinformaticien Java/Perl
    Inscrit en
    Avril 2008
    Messages
    210
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Vienne (Poitou Charente)

    Informations professionnelles :
    Activité : Bioinformaticien Java/Perl
    Secteur : Santé

    Informations forums :
    Inscription : Avril 2008
    Messages : 210
    Points : 263
    Points
    263
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    my @out = sort {
     
             $a = $a =~ /(\d+,\d+)\D+/;
             $b = $b =~ /(\d+,\d+)\D+/;
     
             (split ',', $a) <=> (split ',', $b)
    je suppose que comme ça c'est mieux (pas encore tester !)
    CKL
    N°°b forever
    --
    may the be with you

  7. #7
    Membre émérite
    Avatar de Jasmine80
    Femme Profil pro
    Bioinformaticienne
    Inscrit en
    Octobre 2006
    Messages
    3 157
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 44
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Bioinformaticienne
    Secteur : Santé

    Informations forums :
    Inscription : Octobre 2006
    Messages : 3 157
    Points : 2 673
    Points
    2 673
    Par défaut
    Tu n'as pas compris le principe. Tu as deux parties séparées par ||. Tu commences par comparer les deux valeurs entières et ensuite, si elles sont égales tu effectues la seconde partie qui compare les parties décimales.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
             (split ',', $a)[0] <=> (split ',', $b)[0]  ||
             (split ',', $a)[1] <=> (split ',', $b)[1]
    Si tu ne mets qu'une partie à ton 'sort', le tri sera numérique sur l'entièreté de tes valeurs (partie entière et partie décimale prise en compte en même temps) et ton .9 dera évidemment considéré comme .90 et donc placé après ton .13

    Est-ce clair? Tu peux aller voir la documentation du lien.
    -- Jasmine --

  8. #8
    Expert éminent
    Avatar de Jedai
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2003
    Messages
    6 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Avril 2003
    Messages : 6 245
    Points : 8 586
    Points
    8 586
    Par défaut
    En bref tu veux trier des chiffres décimaux mais ils ne sont pas au bon format, c'est ça ?

    Si le changement de format ne te dérange pas, tu peux juste en passer par la comparaison numérique :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    s/(\d+),/$1./ foreach @list;
    { no warnings "numeric"; @list = sort { $a <=> $b } @list; }
    # optionel pour en revenir aux virgules :
    # s/(\d+)./$1,/ foreach @list;
    fera ce que tu veux (mais les virgules seront remplacés par des points, enfin tu peux toujours inverser ceci après).

    --
    Jedaï

  9. #9
    Membre émérite
    Avatar de Jasmine80
    Femme Profil pro
    Bioinformaticienne
    Inscrit en
    Octobre 2006
    Messages
    3 157
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 44
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Bioinformaticienne
    Secteur : Santé

    Informations forums :
    Inscription : Octobre 2006
    Messages : 3 157
    Points : 2 673
    Points
    2 673
    Par défaut
    j'avais pensé à cette méthode sauf que 19.10 seras AVANT 19.9 alors que justement je ne veut pas !

    Il ne veut pas que ses valeurs soient traitées comme des nombres décimaux mais que la partie décimale soit traitée comme une partie entière et donc que .9 passe avant .10
    -- Jasmine --

  10. #10
    Expert éminent
    Avatar de Jedai
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2003
    Messages
    6 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Avril 2003
    Messages : 6 245
    Points : 8 586
    Points
    8 586
    Par défaut
    Citation Envoyé par Jasmine80 Voir le message
    Il ne veut pas que ses valeurs soient traitées comme des nombres décimaux mais que la partie décimale soit traitée comme une partie entière et donc que .9 passe avant .10
    Ah effectivement... Dans ce cas, ta méthode est correcte (bien que l'implémentation soit loi d'être optimale) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    my @sorted_list =
      map { $_->[2] }
        sort { $a->[0] <=> $b->[0] || $a->[1] <=> $b->[1] }
          map { m/^(\d+),(\d+)\D$/; [ $1, $2, $_ ] }
            @list;
    sera plus rapide (Schwartzian Transform), ou même utiliser l'un des Sort modules du CPAN.

    --
    Jedaï

  11. #11
    Membre émérite
    Avatar de Jasmine80
    Femme Profil pro
    Bioinformaticienne
    Inscrit en
    Octobre 2006
    Messages
    3 157
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 44
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Bioinformaticienne
    Secteur : Santé

    Informations forums :
    Inscription : Octobre 2006
    Messages : 3 157
    Points : 2 673
    Points
    2 673
    Par défaut
    Pourrais-tu expliquer ton code s'il te plait.

    Pourquoi commence t'on par cette ligne?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      map { m/^(\d+),(\d+)\D$/; [ $1, $2, $_ ] }
    Donc ici on vérifie que la liste [ $1, $2, $_ ] match bien ? Que contient $_


    Merci beaucoup,
    -- Jasmine --

  12. #12
    Expert éminent
    Avatar de Jedai
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2003
    Messages
    6 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Avril 2003
    Messages : 6 245
    Points : 8 586
    Points
    8 586
    Par défaut
    Tu as une explication dans le lien que tu as donné plus tôt. Les Perliste lui donne un nom "Swartzian Transform" mais c'est une technique très naturelle pour un programmeur ayant l'expérience du paradigme fonctionnel.
    Il faut le lire à l'envers, de bas en haut (enfin si tu n'as pas d'expérience avec, ça se lit bien de haut en bas pour un habitué).
    L'idée est de commencer par transformer ton tableau en tableau 2D, chaque élément étant rassemblé avec ses clés de tri :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    map { m/^(\d+),(\d+)\D$/; [ $1, $2, $_ ] }
    ici je crée pour chaque élément de @list un tableau anonyme contenant le premier nombre, le deuxième nombre et l'élément d'origine.

    Ensuite on tri normalement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sort { $a->[0] <=> $b->[0] || $a->[1] <=> $b->[1] }
    sur le premier nombre et le deuxième nombre.

    Puis on reextrait les éléments d'origine en jetant les clés de tri :
    Et au final on obtient notre tableau trié.

    Cette technique est relativement efficace, elle ne pollue pas l'espace de nom, elle ne calcule que O(n) fois la clé de tri au lieu de O(n*ln(n)). Pour faire mieux en Perl, il faut en revenir au tri par défaut (sort sans subroutine de tri) ce qui est faisable mais illisible, le mieux est de le faire faire par un module de tri comme Sort::Maker par exemple.

    (Je rappelle quelques éléments clés : dans la subroutine passée à map, $_ est l'élément du tableau entrant, les regexps sans "=~" s'appliquent par défaut à $_)

    --
    Jedaï

  13. #13
    Membre émérite
    Avatar de Jasmine80
    Femme Profil pro
    Bioinformaticienne
    Inscrit en
    Octobre 2006
    Messages
    3 157
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 44
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Bioinformaticienne
    Secteur : Santé

    Informations forums :
    Inscription : Octobre 2006
    Messages : 3 157
    Points : 2 673
    Points
    2 673
    Par défaut
    Merci beaucoup pour les explications, c'est vraiment très clair dans mon esprit maintenant.
    -- Jasmine --

  14. #14
    Membre actif Avatar de CKLN00
    Homme Profil pro
    Bioinformaticien Java/Perl
    Inscrit en
    Avril 2008
    Messages
    210
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Vienne (Poitou Charente)

    Informations professionnelles :
    Activité : Bioinformaticien Java/Perl
    Secteur : Santé

    Informations forums :
    Inscription : Avril 2008
    Messages : 210
    Points : 263
    Points
    263
    Par défaut
    Woaw ! heu et bha alors heu bien merci beaucoup !
    j'ai appris des choses bien intéressantes !
    CKL
    N°°b forever
    --
    may the be with you

  15. #15
    Membre émérite
    Avatar de Jasmine80
    Femme Profil pro
    Bioinformaticienne
    Inscrit en
    Octobre 2006
    Messages
    3 157
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 44
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Bioinformaticienne
    Secteur : Santé

    Informations forums :
    Inscription : Octobre 2006
    Messages : 3 157
    Points : 2 673
    Points
    2 673
    Par défaut
    Oui, moi aussi je vais d'ailleurs lire en détails la documentation sur les tris.
    -- Jasmine --

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Tri complexe avec xsl:sort
    Par jesemeatoutvent dans le forum XSL/XSLT/XPATH
    Réponses: 2
    Dernier message: 17/01/2009, 21h53
  2. tri complexe Transformée Schwartzienne
    Par Jasmine80 dans le forum Langage
    Réponses: 3
    Dernier message: 14/11/2008, 09h03
  3. Réponses: 6
    Dernier message: 14/06/2008, 17h46
  4. tri complexe mysql
    Par jeroen dans le forum Requêtes
    Réponses: 4
    Dernier message: 22/11/2007, 17h42
  5. Tri complexe sur une table
    Par fwdavy dans le forum Requêtes
    Réponses: 1
    Dernier message: 15/11/2007, 23h40

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo