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 :

Utilisation de la fonction sort


Sujet :

Langage Perl

  1. #1
    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 Utilisation de la fonction sort
    Bonjour à tous,


    J'aimerais un peu d'aide afin de réussir à trier mon array, selon la valeur numérique de S, puis celle de A :

    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
    #!/usr/bin/perl
     
    use strict;
    use warnings;
     
     
    my @sample_name = qw /FP014SC_A12_S7
    FP014SC_A12_S5
    FP014SC_A1_S5
    FP014SC_A15_S5
    FP014SC_A16_S6
    FP014SC_A2_S6/;
     
     
    # d'abord, tous les S1 (de A1 à A16), puis les S2 (de A1 à A16)  ...
     
    @sample_name = map {  sort {$a<=>$b} $_[1]} map {  sort {$a<=>$b} $_[2]} map {split ('_', $_)} @sample_name;
     
    print join("\t", @sample_name), "\n";
    D'avance merci,
    -- Jasmine --

  2. #2
    Membre confirmé
    Avatar de cmcmc
    Homme Profil pro
    Inscrit en
    Juillet 2013
    Messages
    316
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2013
    Messages : 316
    Points : 641
    Points
    641
    Par défaut
    Vite fait (je suis à la bourre...) :
    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
    22
    Taisha:~/perl/forum $ perl -E '
    my @sample_name = qw /FP014SC_A12_S7
     FP014SC_A12_S5
     FP014SC_A1_S5
     FP014SC_A15_S5
     FP014SC_A16_S6
     FP014SC_A2_S6/;
    my @sorted = map { join "", @$_ }
                 sort { $a->[3] <=> $b->[3] or $a->[1] <=> $b->[1] }
                 map {
                   my @decomposition = m/^(.*_A)(\d+)(_S)(\d+)$/
                     or die "erreur de format: \047$_\047";
                   [ @decomposition ]
                 } @sample_name;
    say for @sorted'
    FP014SC_A1_S5
    FP014SC_A12_S5
    FP014SC_A15_S5
    FP014SC_A2_S6
    FP014SC_A16_S6
    FP014SC_A12_S7
    Taisha:~/perl/forum $
    Si tu as des questions n'hésite pas.
    Sauf indication contraire tous les codes que je présente sont utilisables et testés (mais sans garantie d'aucune sorte)
    J'apporte beaucoup de soin à la rédaction de mes posts et apprécie les retours donc merci de s'il vous paraissent pertinents ou utiles
    Lazyness, Impatience and Hubris are good for you

  3. #3
    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
    Ah c'est vraiment super ! Merci beaucoup, surtout que tu étais à la bourre.
    Il y a juste cette partie que je ne comprends pas : [ @decomposition ] ... mais, les explications peuvent attendre quelques jours ... ça fonctionne, et je peux continuer mon code.
    Encore merci pour ton aide.
    -- Jasmine --

  4. #4
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Permet de créer un tableau (array) anonyme contenant @decomposition (la décomposition du texte en clés de tri).
    Chaque élément retourné par map sera donc une référence à un tableau et dans la routine de tri, $a->[3] fera référence au 4e élément décomposé d'une ligne, et $a->[1] au 2e élément décomposé.
    Le map du début du pipeline va reconstruire les lignes d'origine après avoir été triées en procédant par join "", @$_

    Cette opération de tri utilise la technique de la transformée Schwartzienne
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  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 compris le traitement des données, mais il va falloir que je m'entraine avant de réussir seule.
    Merci beaucoup pour ces explications et ce lien.
    -- Jasmine --

  6. #6
    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
    Je revoyais le code, pour essayer de bien m'ancrer son fonctionnement dans la tête ... puis, je me suis demandée, pourquoi utiliser un 'or' dans le map du tri ?
    -- Jasmine --

  7. #7
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Points : 12 469
    Points
    12 469
    Billets dans le blog
    1
    Par défaut
    La première comparaison renvoie 0 (si les clefs sont égales), 1 ou -1 si l'une ou l'autre est plus grande que l'autre. Si elle donne 1 ou -1, alors la première comparaison suffit à ordonner les deux valeurs, inutile de comparer les secondes valeurs. Si elle donne 0 (premières clefs égales), alors il faut comparer les deuxièmes clefs. Si la première comparaison renvoie 0 (soit le booléen 0), alors le or force d'exécution de la seconde comparaison. Sinon, la première comparaison est évaluée à vrai, alors le second terme du or (la seconde comparaison) n'est pas exécuté (court-circuité).

    Autrement dit, le or optimise le sort en n'effectuant la seconde comparaison que quand celle-ci est nécessaire.

  8. #8
    Membre confirmé
    Avatar de cmcmc
    Homme Profil pro
    Inscrit en
    Juillet 2013
    Messages
    316
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2013
    Messages : 316
    Points : 641
    Points
    641
    Par défaut
    à Philou67430 et Lolo78 pour leurs explications . Quelques compléments :

    Le point fondamental est effectivement [ @decomposition ]. Le principe à retenir pour ce genre de problème est de décomposer l'élément sur lequel on doit travailler, pour le mettre sous une forme qui facilite son exploitation lors du tri. C'est le but de la décomposition. Le problème est, comment faire en sorte que le résultat de la décomposition constitue un élément unique de la liste passée à sort ? Si on retourne directement la liste elle est aplatie avec les autres :
    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
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    Taisha:~/perl/forum $ perl -MData::Dump -E '
    my @sample_name = qw /FP014SC_A12_S7
     FP014SC_A12_S5
     FP014SC_A1_S5
     FP014SC_A15_S5
     FP014SC_A16_S6
     FP014SC_A2_S6/;
    dd map {
             my @decomposition = m/^(.*_A)(\d+)(_S)(\d+)$/
               or die "erreur de format: \047$_\047";
             @decomposition
           } @sample_name;
    '
    (
      "FP014SC_A",
      12,
      "_S",
      7,
      "FP014SC_A",
      12,
      "_S",
      5,
      "FP014SC_A",
      1,
      "_S",
      5,
      "FP014SC_A",
      15,
      "_S",
      5,
      "FP014SC_A",
      16,
      "_S",
      6,
      "FP014SC_A",
      2,
      "_S",
      6,
    )
    Taisha:~/perl/forum $
    On utilise ici le constructeur [ ... ] pour créer une référence à une liste, et [ @decomposition ] est du coup une référence à une liste copie de @decomposition. C'est cette référence qui est renvoyée par le map, à raison d'une référence par élément initial :
    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
    22
    Taisha:~/perl/forum $ perl -MData::Dump -E '
    my @sample_name = qw /FP014SC_A12_S7
     FP014SC_A12_S5
     FP014SC_A1_S5
     FP014SC_A15_S5
     FP014SC_A16_S6
     FP014SC_A2_S6/;
    dd map {
             my @decomposition = m/^(.*_A)(\d+)(_S)(\d+)$/
               or die "erreur de format: \047$_\047";
             [ @decomposition ]
           } @sample_name;
    '
    (
      ["FP014SC_A", 12, "_S", 7],
      ["FP014SC_A", 12, "_S", 5],
      ["FP014SC_A", 1, "_S", 5],
      ["FP014SC_A", 15, "_S", 5],
      ["FP014SC_A", 16, "_S", 6],
      ["FP014SC_A", 2, "_S", 6],
    )
    Taisha:~/perl/forum $
    A cause de l'opération de copie ce n'est pas particulièrement efficace et il vaut en fait mieux l'écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
                 map {
                   my @decomposition = m/^(.*_A)(\d+)(_S)(\d+)$/
                     or die "erreur de format: \047$_\047";
                   \@decomposition
                 }
    qui fonctionne parce que la déclaration my @decomposition garantit ici qu'une nouvelle liste est créée à chaque itération de la boucle. Si on supprime le my, c'est la cata :
    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
    22
    Taisha:~/perl/forum $ perl -E '
    my @sample_name = qw /FP014SC_A12_S7
     FP014SC_A12_S5
     FP014SC_A1_S5
     FP014SC_A15_S5
     FP014SC_A16_S6
     FP014SC_A2_S6/;
    my @sorted = map { join "", @$_ }
                 sort { $a->[3] <=> $b->[3] or $a->[1] <=> $b->[1] }
                 map {
                   @decomposition = m/^(.*_A)(\d+)(_S)(\d+)$/
                     or die "erreur de format: \047$_\047";
                   \@decomposition
                 } @sample_name;
    say for @sorted'
    FP014SC_A2_S6
    FP014SC_A2_S6
    FP014SC_A2_S6
    FP014SC_A2_S6
    FP014SC_A2_S6
    FP014SC_A2_S6
    Taisha:~/perl/forum $
    car @decomposition devient une variable globale et le map renvoie une liste de références à cette variable...

    L'utilisation du or dans l'expression du tri est un idiome standard et utile à retenir pour le tri multi-critères. Cela fonctionne lorsque les comparaisons $a op $b ou compare($a,$b) renvoient -1 si $a est "avant" $b dans l'ordre désiré, 0 si $a est "à la même place que" $b dans ce même ordre, et 1 si $a est "après" $b. Perl définit deux opérateurs ayant ces caractéristiques : <=> pour les comparaisons numériques, et cmp pour les comparaisons textuelles (attention cependant pour le second au locale d'exécution...). Si un jour tu dois développer un opérateur de comparaison (par exemple, entre couleurs, ou prénoms, ou molécules...) arrange toi pour qu'il ait ce même comportement, cela te permettra de l'intégrer dans des tris multi-critères. En standard sort { $a op $b } produit un tri par ordre ascendant. Si on veut un ordre descendant il suffit d'inverser les positions de $a et $b.

    Si le sujet t'intéresse tu trouveras pleins d'infos dans cet article.
    Sauf indication contraire tous les codes que je présente sont utilisables et testés (mais sans garantie d'aucune sorte)
    J'apporte beaucoup de soin à la rédaction de mes posts et apprécie les retours donc merci de s'il vous paraissent pertinents ou utiles
    Lazyness, Impatience and Hubris are good for you

  9. #9
    Membre confirmé
    Avatar de cmcmc
    Homme Profil pro
    Inscrit en
    Juillet 2013
    Messages
    316
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2013
    Messages : 316
    Points : 641
    Points
    641
    Par défaut
    Citation Envoyé par Philou67430 Voir le message
    Cette opération de tri utilise la technique de la transformée Schwartzienne
    Disons plutôt un map/sort/map. La 'transformée Schwarzienne' canonique dans ce cas aurait me semble-t-il été
    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
    Taisha:~/perl/forum $ perl -E '
    my @sample_name = qw /FP014SC_A12_S7
     FP014SC_A12_S5
     FP014SC_A1_S5
     FP014SC_A15_S5
     FP014SC_A16_S6
     FP014SC_A2_S6/;
    my @sorted = map $_->[0] =>
                 sort { $a->[1] <=> $b->[1] or $a->[2] <=> $b->[2] }
                 map { [ $_, reverse m/^.*_A(\d+)_S(\d+)$/ ] }
                 @sample_name;
    say for @sorted'
    FP014SC_A1_S5
    FP014SC_A12_S5
    FP014SC_A15_S5
    FP014SC_A2_S6
    FP014SC_A16_S6
    FP014SC_A12_S7
    Taisha:~/perl/forum $
    Sauf indication contraire tous les codes que je présente sont utilisables et testés (mais sans garantie d'aucune sorte)
    J'apporte beaucoup de soin à la rédaction de mes posts et apprécie les retours donc merci de s'il vous paraissent pertinents ou utiles
    Lazyness, Impatience and Hubris are good for you

  10. #10
    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
    Et bien et bien, que de lecture pour ce matin, et ainsi bien démarrer la journée. Merci à tous pour ces explications très claires. Pour une fois, j'ai dix fois plus de commentaires que de code .
    Je n'ai pas encore regardé le lien 'A Fresh Look at Efficient Perl Sorting', mais je compte le faire. Le tri, c'est vraiment un sujet très intéressant, là j'utilise les tutoriels de ce forum 'Programmation fonctionnelle en Perl' de Laurent Rosenfeld, mais je n'ai pas encore tout compris . Je suis contente ce matin, je viens de découvrir le 'ctrl scroll', qui me permet de soulager mes yeux

    C'est grâce à des personnes comme vous que ce forum est si agréable.

    Bonne journée à tous.
    -- Jasmine --

  11. #11
    Membre confirmé
    Avatar de cmcmc
    Homme Profil pro
    Inscrit en
    Juillet 2013
    Messages
    316
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2013
    Messages : 316
    Points : 641
    Points
    641
    Par défaut
    Citation Envoyé par Jasmine80 Voir le message
    Je n'ai pas encore regardé le lien 'A Fresh Look at Efficient Perl Sorting', mais je compte le faire.
    ou si tu préfères lire en français, suis le lien envoyé précédemment par Philou67430 (c'est sa traduction française ).
    Sauf indication contraire tous les codes que je présente sont utilisables et testés (mais sans garantie d'aucune sorte)
    J'apporte beaucoup de soin à la rédaction de mes posts et apprécie les retours donc merci de s'il vous paraissent pertinents ou utiles
    Lazyness, Impatience and Hubris are good for you

  12. #12
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Points : 12 469
    Points
    12 469
    Billets dans le blog
    1
    Par défaut
    Bonjour Jasmine,

    d'abord, merci de tes commentaires.

    Ensuite, je dirais: force toi à faire toi-même une transformation de Schwartz (ou construction map / sort / map) simple (c'est à dire sur un jeu de données et avec des règles de gestion simples). Tu vas peut-être galérer un peu au départ, mais je suis convaincu que tu verras en le réalisant toi-même que c'est en fait très simple.

    Je peux te donner un exemple simple à titre d'exercice, si tu le désires. Je construis un tableau des mois de l'année comme suit:
    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
     
      DB<1> @mois =  qw /jan fev mar avr mai jun  jui aou sep oct nov dec/;
     
      DB<2>  @tableau = sort map { $i++; "$_ : $i";}   @mois;
     
      DB<3> x \@tableau;
    0  ARRAY(0x600508b68)
       0  'aou : 8'
       1  'avr : 4'
       2  'dec : 12'
       3  'fev : 2'
       4  'jan : 1'
       5  'jui : 7'
       6  'jun : 6'
       7  'mai : 5'
       8  'mar : 3'
       9  'nov : 11'
       10  'oct : 10'
       11  'sep : 9'
    Du fait du sort que j'ai mis pour pimenter l'exercice, le tableau @tableau est ordonné par ordre alphabétique des mois, ce qui n'est pas très utile en général.

    L'exercice consiste à repartir du tableau @tableau ainsi construit et à faire une nouvelle version du tableau (ou simplement l'afficher) ordonnée selon le numéro de mois en utilisant la transformation de Schwartz.

    L'idée est qu'il faut essentiellement enchaîner les trois opérations:
    - un map pour transformer chaque élément du tableau d'origine en une structure de données qui pourrait être une référence à un tableau anonyme du genre: [$num_mois, élément d'origine] (soit, par exemple: [1, 'jan : 1']);
    - le sort portant sur le premier champ de chaque tableau anonyme;
    - un map pour renvoyer (après le tri) le second champ des tableaux anonymes triés selon le numéro de mois.

    Essaie de le faire. Si tu n'y arrives pas, montre tes tentatives, on pourra corriger, mais essaie vraiment d'y arriver par toi même, ça te sera plus utile.

  13. #13
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Je ne taquine pas mais, Jasmine, cette transformée ne te rappelle pas quelque chose ?
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  14. #14
    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 lolo, pour ton exercice :

    Je ne sais pas comment lui dire, de prendre le numéro de mois correspondant à la position dans le array @mois.
    Si mois était un hash, dont la clé est le nom du mois et la valeur, le numéro associé, je pourrais faire ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    print map { $_->[1] }
    sort { $a->[0] <=> $b->[0] }
    map {[ $mois{$_},  $_ ]}@tableau;
    Est-ce que c'est bien ça ?
    -- Jasmine --

  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
    J'ai inversé la valeur de la clé et celle de la valeur associée ... ça change quelque chose ?
    -- Jasmine --

  16. #16
    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
    Citation Envoyé par Philou67430 Voir le message
    Je ne taquine pas mais, Jasmine, cette transformée ne te rappelle pas quelque chose ?
    ... sinon, tu aurais pu me taquiner, y'a pas de mal, j'aime bien ça... Lolo aussi, je crois qu'il doit aimer ça

    2008 ... ça date, je ne me souviens même plus de ce que je posais comme questions à cette époque ... enfin ça n'a pas beaucoup évolué depuis, c'est pas top le chômage pour ça !
    -- Jasmine --

  17. #17
    Membre confirmé
    Avatar de cmcmc
    Homme Profil pro
    Inscrit en
    Juillet 2013
    Messages
    316
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2013
    Messages : 316
    Points : 641
    Points
    641
    Par défaut
    Citation Envoyé par Jasmine80 Voir le message
    Merci lolo, pour ton exercice :

    Je ne sais pas comment lui dire, de prendre le numéro de mois correspondant à la position dans le array @mois.
    Si mois était un hash, dont la clé est le nom du mois et la valeur, le numéro associé, je pourrais faire ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    print map { $_->[1] }
    sort { $a->[0] <=> $b->[0] }
    map {[ $mois{$_},  $_ ]}@tableau;
    Est-ce que c'est bien ça ?
    Non, tu ne dois pas te servir du tableau @mois... Pour éviter la tentation, initialise @tableau dans ton script comme suit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    my @tableau = sort map { $i++; "$_ : $i";} qw /jan fev mar avr mai jun  jui aou sep oct nov dec/;
    Sauf indication contraire tous les codes que je présente sont utilisables et testés (mais sans garantie d'aucune sorte)
    J'apporte beaucoup de soin à la rédaction de mes posts et apprécie les retours donc merci de s'il vous paraissent pertinents ou utiles
    Lazyness, Impatience and Hubris are good for you

  18. #18
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Points : 12 469
    Points
    12 469
    Billets dans le blog
    1
    Par défaut
    OK, Jasmine, tu as ce tableau tout simple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
       0  'aou : 8'
       1  'avr : 4'
       2  'dec : 12'
       3  'fev : 2'
       4  'jan : 1'
       5  'jui : 7'
       6  'jun : 6'
       7  'mai : 5'
       8  'mar : 3'
       9  'nov : 11'
       10  'oct : 10'
       11  'sep : 9'
    Prenons par exemple le premier élément: "aou : 8". Tu fais comment pour récupérer les deux morceaux qui t'intéressent? Tu sais très bien faire cela. Tu peux au choix utiliser une expression régulière ou un split (ou encore une autre méthode si tu préfères). Par exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
      DB<6>  @morceaux = split /[: ]+/, "aou : 8";
     
      DB<7> x \@morceaux;
    0  ARRAY(0x6005008a8)
       0  'aou'
       1  8
    Ici, on cherche juste à récupérer le numéro de mois, donc, par exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
      DB<8> $num = (split /[: ]+/, "aou : 8")[1];
     
      DB<9> p $num
    8
    Il suffit donc d'appliquer ce split à chaque élément du tableau et obtenir pour chaque élément une structure du genre " [8, 'aou : 8'], c'est-à-dire le numéro de mois et la chaîne d'origine. Tu peux faire cela avec un map:
    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
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
      DB<1> @tableau = sort  map { $i++; "$_ : $i";}  qw /jan fev mar avr mai jun  jui aou sep oct nov dec/;
    
      DB<2>  x \@tableau;
    0  ARRAY(0x600500bd8)
       0  'aou : 8'
       1  'avr : 4'
       2  'dec : 12'
       3  'fev : 2'
       4  'jan : 1'
       5  'jui : 7'
       6  'jun : 6'
       7  'mai : 5'
       8  'mar : 3'
       9  'nov : 11'
       10  'oct : 10'
       11  'sep : 9'
      DB<3>  @tmp_tab = map { my $num = (split  /[: ]+/, $_)[1];  [$num, $_]}  @tableau;
    
      DB<4> x \@tmp_tab;
    0  ARRAY(0x6005009e0)
       0  ARRAY(0x600500938)
          0  8
          1  'aou : 8'
       1  ARRAY(0x6005d15a8)
          0  4
          1  'avr : 4'
       2  ARRAY(0x6005d1608)
          0  12
          1  'dec : 12'
       3  ARRAY(0x6005d1668)
          0  2
          1  'fev : 2'
       4  ARRAY(0x6005d16c8)
          0  1
          1  'jan : 1'
       5  ARRAY(0x6005d1b78)
          0  7
          1  'jui : 7'
       6  ARRAY(0x6005d1bd8)
          0  6
          1  'jun : 6'
       7  ARRAY(0x6005d2a60)
          0  5
          1  'mai : 5'
       8  ARRAY(0x6005d2ac0)
          0  3
          1  'mar : 3'
       9  ARRAY(0x6005d2b20)
          0  11
          1  'nov : 11'
       10  ARRAY(0x6005d2b80)
          0  10
          1  'oct : 10'
       11  ARRAY(0x6005d2be0)
          0  9
          1  'sep : 9'
      DB<5>
    La ligne importante ici est DB<3>, le reste n'est que de la préparation ou de l'affichage des structures de données.

    Ce tableau temporaire @tmp_tab (qui est en fait inutile et dont on se passera ensuite) a maintenant la bonne structure pour permettre un tri sur le numéro de mois. En fait, il serait peut-être plus clair de le décrire ainsi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    (
       [8, 'aou : 8'],
       [4, 'avr : 4'],
       [12, 'dec : 12'],
       ...
    )
    Réfléchis maintenant à comment tu trierais ce tableau temporaire sur le premier champ de chaque élément pour qu'il respecte l'ordre des mois. Mets le résultat dans un second tableau temporaire. Puis, si tu y arrives, extrais de ce second tableau temporaire le deuxième champ pour obtenir le troisième tableau, qui contiendra alors ( 'jan : 1', fev : 2', ...).

    Remarque: le but pour l'instant est bien d'obtenir quelque chose du genre "( 'jan : 1', 'fev : 2', ...)", c'est-à-dire exactement le tableau d'origine, mais trié selon l'ordre normal des mois. On pourra par la suite modifier légèrement le code pour obtenir, si on le désire, uniquement les mois sans leur numéro.

  19. #19
    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 pour vos réponses. Je ne sais pas si j'aurai le temps d'y regarder aujourd'hui, mais ce sera fait pour la semaine prochaine au plus tard. Biz.
    -- Jasmine --

  20. #20
    Membre confirmé
    Avatar de cmcmc
    Homme Profil pro
    Inscrit en
    Juillet 2013
    Messages
    316
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2013
    Messages : 316
    Points : 641
    Points
    641
    Par défaut
    Citation Envoyé par Jasmine80 Voir le message
    J'ai inversé la valeur de la clé et celle de la valeur associée ... ça change quelque chose ?
    Tu peux utiliser l'ordre que tu veux mais il y a en fait une raison pour laquelle la transformée Schwartzienne a la forme canonique
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    @sorted = map $_->[0] => sort ... map ... @data;
    Il faut ici lire de droite à gauche : on commence par calculer map ... @data, dont le résultat va alimenter sort ..., dont le résultat va lui même finalement alimenter map $_->[0] =>.

    Petit rappel : l'opérateur map peut prendre deux formes : map BLOC liste ou map EXPR , liste. Note bien la présence d'une virgule pour distinguer les deux formes. Par exemple, pour calculer la liste contenant les carrés des nombres d'une autre liste, on peut utiliser map { $_*$_ } @input ou map $_*$_ , @input. La "grosse virgule" (en anglais fat comma) => peut être utilisée en lieu et place de la virgule simple mais c'est une simple coquetterie; la seule différence est que => permet de ne pas quoter la valeur à sa gauche si c'est une chaîne de caractères, ce qui est utile notamment lors de l'initialisation de hashes : ainsi %h = (one => 1, two => 2, three => 3) est plus lisible que %h = ('one', 1, 'two', 2, 'three', 3). Ici ça n'a pas d'impact autre que cosmétique. Pour autant c'est un usage consacré et pour beaucoup de perliens le fait de voir map $_->[0] => au début d'une expression annonce effectivement une transformée Schwartzienne.

    A elle seule la partie map $_->[0] => est riche d'information : on voit que ce map va traiter une liste dont chaque item est une référence (puisqu'on déréférence $_ : $_->...) à un tableau (à cause des crochets $_->[...]). Pour chaque item, il renvoie le premier élément du tableau référencé.

    Comme ce qu'on cherche ici à faire, c'est un tri, on veut que la liste finale soit le résultat du tri de la liste initiale. Ergo, le premier élément du tableau référencé ci-dessus doit être un élément de la liste d'origine. Comme le tri lui même ne modifie pas les items sur lesquels il opère, cela veut dire que le premier map (dans l'ordre chronologique) map ... est forcément de la forme map { ... ; [ $_, ...] } (ou peut-être dans les cas les plus simples map [ $_, ...] =>).

    Pourquoi est-il logique (et donc important ) que l'élément de la liste originale véhiculé dans le tableau intermédiaire soit en première position (à l'index 0) et non en seconde ou ailleurs ? Parce que c'est la seule position qui soit stable quelle que soit la taille du tableau. Typiquement, on va placer à l'index 1 le premier critère de tri, à l'index 2 le second critère de tri, etc. Et on écrira le corps du tri comme suit : sort { $a->[1] op1 $b->[1] or $a->[2] op2 $b->[2] or ... } (où op1, op2, etc. sont typiquement <=> ou cmp, comme évoqué précédemment). Tout au moins si on veut trier chaque champ par ordre ascendant : si le champ N doit être trié par ordre descendant il suffit d'inverser les position de $a et $b pour ce champ, i.e. ... or $b->[N] opN $a->[N] or ... .

    La forme générale de la transformée Schwartzienne est donc assez codifiée : le map final map $_->[0] => est fixé, le corps du sort ... est également fixé par le nombre, la nature et l'importance relative des critères de tri, et de l'ordre (ascendant ou descendant) désiré pour chacun d'entre eux. La seule place pour un peu de créativité est dans le map ... initial, qui va extraire ou construire les critères utilisés par le tri.

    Incidemment, on peut définir une transformée Schwartzienne identité. Ainsi, une manière coûteuse mais parfaitement correcte de copier une liste est
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    @copy = do { use sort qw(stable); map $_->[0] => sort { 0 } map [$_] =>  @data };
    Je te laisse méditer sur la signification exacte de sort { 0 } et sur l'intérêt ici de use sort qw(stable); ce ne sera pas du temps perdu

    A ce stade tu devrais avoir tous les éléments nécessaires pour résoudre de manière canonique le problème posé par Lolo78. Je conclurai en remarquant que si dans beaucoup de cas, le map ... initial effectue une extraction de données des éléments d'origine, il arrive également qu'on fasse un calcul à partir des constituants de ces élements. Considérons par exemple le problème d'ordonner, selon leur distance à l'origine, des points dans le plan représentés par des tableaux [abscisse, ordonnée]. On peut le faire par la transformation suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Taisha:~/perl/forum $ perl -MData::Dump -E '
    dd map $_->[0] =>
       sort { $a->[1] <=> $b->[1] }
       map [$_, sqrt($_->[0]*$_->[0] + $_->[1]*$_->[1])] =>
       [1, 1], [0, 1], [2, 2], [1, 2]'
    ([0, 1], [1, 1], [1, 2], [2, 2])
    Taisha:~/perl/forum $
    Une variante de la transformée Schwartzienne consiste à sélectionner (sans les trier) des items de la liste d'origine, par exemple les points situés à une distance inférieure à un seuil : on peut pour cela utiliser grep en lieu et place du sort
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Taisha:~/perl/forum $ perl -MData::Dump -E '
    dd map $_->[0] =>
       grep { $_->[1] < 2 }
       map [$_, sqrt($_->[0]*$_->[0] + $_->[1]*$_->[1])] =>
       [1, 1], [0, 1], [2, 2], [1, 2]'
    ([1, 1], [0, 1])
    Taisha:~/perl/forum $
    évidemment rien n'empêche de combiner les deux (auquel cas on applique le sort après le grep... Assure toi que tu comprends pourquoi ).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Taisha:~/perl/forum $ perl -MData::Dump -E '
    dd map $_->[0] =>
       sort { $a->[1] <=> $b->[1] }
       grep { $_->[1] < 2 }
       map [$_, sqrt($_->[0]*$_->[0] + $_->[1]*$_->[1])] =>
       [1, 1], [0, 1], [2, 2], [1, 2]'
    ([0, 1], [1, 1])
    Taisha:~/perl/forum $
    Sauf indication contraire tous les codes que je présente sont utilisables et testés (mais sans garantie d'aucune sorte)
    J'apporte beaucoup de soin à la rédaction de mes posts et apprécie les retours donc merci de s'il vous paraissent pertinents ou utiles
    Lazyness, Impatience and Hubris are good for you

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Réponses: 4
    Dernier message: 24/05/2009, 18h35
  2. Réponses: 3
    Dernier message: 19/11/2007, 19h36
  3. [STL] Débutant : problème utilisation fonction Sort
    Par marcootz dans le forum SL & STL
    Réponses: 5
    Dernier message: 29/08/2007, 20h19
  4. Utilisation de la fonction qsort
    Par Jsmeline dans le forum C
    Réponses: 8
    Dernier message: 28/01/2005, 12h40
  5. [LG]librairies : utiliser seulement quelques fonctions
    Par wwwroom dans le forum Langage
    Réponses: 13
    Dernier message: 14/05/2004, 22h50

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