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 et traitement (un peu spécial) sur tableaux multidimensionnels


Sujet :

Langage Perl

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 37
    Points : 12
    Points
    12
    Par défaut Tri et traitement (un peu spécial) sur tableaux multidimensionnels
    Bonjour à tous ,

    Vivant chichement sur mes maigres «*acquis*» en Perl, cela faisait un moment que je n'étais pas venu demander un conseil concernant un programme. Mais voilà... cette fois-ci, après une longue série d'essais, il semble que mon objectif est au-delà de mes faibles compétences actuelles . Toute aide sera bien entendu plus que la bienvenue et je vous en remercie vivement d'avance.

    Grosso modo, il s'agit de manipuler un fichier CSV / tableau multidimensionnel dont la structure initiale ressemble à :

    Ma,10,0,5,4,1,0,....,5
    Mb,0,1,4,16,4,7,....,1
    Mc,4,3,2,11,1,1,....,17
    Md,4,2,1,11,1,1,....,1
    Me,3,4,5,2,5,3,....,6
    Mx,........................,4

    Ce que je souhaite faire :
    1. Charger le tableau / fichier (OK, même en multidimensionnel ; cf le code ci-dessous).
    2. Faire un tri décroissant sur la colonne 2 (à partir de [0][1] donc), en faisant «*bouger*» tout le tableau en fonction dudit tri.
    3. Affecter des rangs à la colonne 2 en fonction de ce même tri. Dans cet exemple et sur cette colonne 2, cela donnerait par exemple :

    CSV => Rang(s)
    10 => 1
    4 => 2
    4 => 2
    3 => 3

    2 => 4
    2 => 4
    1 => 5
    0.5 => 6
    0.5 => 6

    0 => x

    4. Reproduire l'opération 2 et 3 sur chacune des colonnes.

    => Tout ça pour obtenir un tableau où les fréquences seraient remplacées par des rangs.

    Malheureusement, je ne connais rien (et après lecture de différents sites, il semble bien que je ne comprenne rien) à la syntaxe liée aux tableaux multidimensionnels. Pour le moment, la seule chose que j'ai réussi à faire est de charger mon fichier dans un tableau, avec – par exemple - :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    open (FICH, "final.csv") || die ("pas de fichier CSV\n"); 
    while (<FICH>) 
    {
            @tmp = split(/[,]/);
            push @tabtab, [ @tmp ];
    }
    close (FICH);
    Ensuite, c'est le vide total (car je ne sais ni comment trier, ni comment pointer dans les tableaux multidimensionnels, ni comment en modifier les valeurs). Si quelqu'un à une idée pour arriver à ce code ce serait fabuleux et je vous en remercie beaucoup .
    Cordialement.

  2. #2
    Responsable Perl et Outils

    Avatar de djibril
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    19 820
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 19 820
    Points : 498 771
    Points
    498 771
    Par défaut
    Pour que l'on puisse t'aider, il faut déjà que l'on comprenne ce que tu veux, et là ton explication ne l'est pas, surtout le partie sur les rangs.

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 37
    Points : 12
    Points
    12
    Par défaut
    Merci Djibril et désolé si je n'ai pas été assez clair.
    Je vais tenter de faire mieux.

    Je possède un tableau du type :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    Mod1,12,1,4,7,8
    Mod2,4,1,2,6,7
    Mod3,4,1,1,5,2
    Mod4,1,3,2,4,6
    Mod5,6,2,2,1,6
    Mod6,8,3,1,1,5
    Mod7,6,4,2,1,5
    Mod8,5,2,1,3,5
    Mod9,1,5,2,3,4
    Mod10,1,6,3,2,4
    Mod11,1,12,3,2,4
    Chargé dans un array multidimensionnel.
    Et je veux le transformer en tableau du type :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    Mod1,1,7,1,1,1
    Mod2,5,7,3,2,2
    Mod3,5,7,4,3,6
    Mod4,6,5,3,4,3
    Mod5,3,7,3,7,3
    Mod6,2,5,4,7,4
    Mod7,3,4,3,7,4
    Mod8,4,6,4,5,4
    Mod9,6,3,3,5,5
    Mod10,6,2,2,6,5
    Mod11,6,1,2,6,5
    Il s'agit donc d'affecter, dans chaque colonne, le rang 1 au(x) nombre(s) le plus élevé, le rang 2 à celui (ceux) qui vient (viennent) ensuite, et ainsi de suite.
    En regardant la structure du second tableau les choses deviennent plus nettes je pense.

    Au départ, mon tableau initial se trouve dans un fichier CSV. Je le charge donc dans un tableau multidimensionnel, avec le code suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    open (FICH, "final.csv") || die ("pas de fichier CSV\n"); 
    while (<FICH>) 
    {
            @tmp = split(/[,]/);
            push @tabtab, [ @tmp ];
    }
    close (FICH);
    Ensuite, pour arriver à transformer le tableau et attribuer un rang à chaque case, j'ai imaginé – peut-être à tord – que je devais pour chaque colonne, l'une après l'autre : 1. faire un tri décroissant. 2. attribuer des rangs à partir de ce tri (score le plus haut = rang un ; second score = rang deux ; etc.).

    Cependant, je ne sais pas si a. C'est la bonne méthode. b. Le cas échéant, comment faire des tris sur ce type de tableaux, des remplacements, etc.

    Est-ce plus clair comme ça s'il te plaît ? Merci beaucoup pour ton aide.
    Cordialement.

  4. #4
    Responsable Perl et Outils

    Avatar de djibril
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    19 820
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 19 820
    Points : 498 771
    Points
    498 771
    Par défaut
    Ok, c'est plus clair, mais pour mon cerveau, il est tard donc lui n'est plus clair , donc j'y réfléchirais demain. Mais je pense que certaines personnes sur ce forum seront content de se prendre au jeu de l'algo à trouver .

  5. #5
    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
    Une chose n'est toujours pas claire : tu parles de faire un tri décroissant sur la 2e colonne (indice 1), en déplaçant les lignes de sorte que cette 2e colonne soit triée (puis affecter les rangs). Cependant, je ne vois pas que les lignes aient été déplacées dans ton exemple.
    Pourrais-tu, pour que l'on comprenne vraiment bien, donner l'exemple d'une seule étape de remplacement en rang pour UNE colonne.

    Cependant, si j'ai bien compris, tu souhaites pour chaque colonne à partir de la deuxième, définir l'ordre des valeurs dans cette colonne et remplacer la valeur par ce rang. Pour cela, il me semble inutile de trier les lignes complètes. Il suffit en fait, de trier chaque colonne. Perl ne permet pas nativement de traiter des colonnes de tableaux multi-dimensionnels, mais plusieurs modules le permettent. J'en ai déjà utilisé un qui était bien, mais ne le retrouvant plus, je tente avec Data::Table

    Cependant, les premiers essais sont infructueux, car ce module contient des tas de contraintes d'utilisation, qui ne le rendent pas souple à utiliser. Je cherche encore un autre module plus facile d'utilisation avant de poster le code développé.

  6. #6
    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
    Question annexe : quel rang donner à des valeurs identiques ?

  7. #7
    Membre du Club
    Homme Profil pro
    Inscrit en
    Février 2009
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2009
    Messages : 37
    Points : 40
    Points
    40
    Par défaut
    Tel que je le comprend deux valeur identiques prennent le même rang...

    J'ai pas le temps de finir mais un début de piste en inversant la matrice lors de la lecture pour pouvoir trier facilement. Je vais jusqu'à l'affectation des rangs, manque une seconde inverson pour retrouver la bonne disposition.

    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
    59
    60
    61
    62
    63
    64
    65
    66
    use strict;
    use warnings;
     
    my @matrice;
     
    sub invert_matrice($);
     
    open (FH, "< test.txt") or die("$!\n");
     
    # lecture et inversion de la matrcie
    while(<FH>)
    {
    	chomp($_);
    	my @temp = split(/\,/,$_);
     
    	for(my $i = 0;$i < @temp;$i++)
    	{
    		push(@{$matrice[$i]}, $temp[$i]);
    	}
    }
    close(FH);
     
    # on garde la premiere ligne (qui correspond a la premiere colonne)
    my @header = shift(@matrice);
     
    # on tri par ordre decroissant chaque entree de la matrice
    my @sorted_matrice;
    my $cpt = 0;
    foreach(@matrice)
    {
    	push(@{$sorted_matrice[$cpt]},(sort {$b <=> $a} (@{$_})));
    	$cpt+=1;
    }
     
    # affectation des rangs
    my @final_matrice;
    my $ligne_idx = 0;
    foreach (@sorted_matrice)
    {
    	my @ligne = @{$_};
    	my $rang = 0;
     
    	for(my $i = 0;$i < @ligne;$i++)
    	{
    		# On ne traite pas la premiere entree
    		if ($i)
    		{
    			# chaque ligne est trie, une difference indique un changement de rang
    			if ($ligne[$i] != $ligne[$i - 1]) {$rang += 1} 
    		}
     
    		push (@{$final_matrice[$ligne_idx]},$rang);
    	}	
    	$ligne_idx += 1;
    }
     
    unshift(@final_matrice,@header);
     
    # On inverse la matrice
     
    foreach (@final_matrice)
    {
    	print "@{$_}\n";
    }
     
    exit 0;
    Il y a surement bien plus simple avec des fonctions de matrice du CPAN...

  8. #8
    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
    N'ayant pas retrouvé le module de traitement de matrice par ligne ou colonne, j'ai refait des fonctions de lecture/ecriture de csv par colonne.
    Le corps de transformation en rang se trouve dans la boucle foreach en fin de script.
    Deux valeurs égale sont, dans cette implémentation, représentées par des rangs différents. Si j'ai le temps, j'apporterai un correctif.
    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
     
    #!/usr/bin/perl
     
    use strict;
    use warnings;
     
    sub from_csv_by_col {
      my ($file) = @_;
     
      my $cols = [];
      open my $F, "<", $file or die "Can't open $file for reading: $!";
      while (<$F>) {
        chomp;
        my @row = split /,/;
        map { push @{$cols->[$_]}, $row[$_] } 0 .. $#row;
      }
     
      return $cols;
    }
     
    sub to_csv_by_col {
      my ($array, $file) = @_;
     
      if (defined $file) {
        open my $F, ">", $file or die "Can't open $file for writing: $!";
      }
      else {
        $file //= *STDOUT;
      }
     
      while (@{$array->[0]}) {
        print join ",", map { shift @{$_} } @$array;
        print "\n";
      }
    }
     
    my $in = from_csv_by_col("table.csv");
     
    # On recopie la première colonne
    my $out = [ splice @$in, 0, 1 ];
     
    foreach my $col (@$in) {
      my $row_index = 0;
      $col = [ sort { $b->[0] <=> $a->[0] } map { [ $_, $row_index++ ] } @$col ];
      my $rang = 0;
      my @new_col;
      $new_col[$_->[1]] = $rang++ foreach @$col;
      push @$out, [ @new_col ];
    }
     
    to_csv_by_col($out);

  9. #9
    Membre à l'essai
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 37
    Points : 12
    Points
    12
    Par défaut
    Merci beaucoup à tous pour votre aide précieuse et pour vos efforts .
    Effectivement, je n'ai pas encore été très clair sur tous les points.

    En effet, ont met un même rang si c'est la même valeur
    D'autre part, j'ai détaillé toutes les opérations sur le tableau initial, afin d'être le plus clair possible :

    Tableau de départ (simple exemple car mon tableau sera sans doute beaucoup plus grand) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    Mod1,12,1,4,7,8
    Mod2,4,1,2,6,7
    Mod3,4,1,1,5,2
    Mod4,1,3,2,4,6
    Mod5,6,2,2,1,6
    Mod6,8,3,1,1,5
    Mod7,6,4,2,1,5
    Mod8,5,2,1,3,5
    Mod9,1,5,2,3,4
    Mod10,1,6,3,2,4
    Mod11,1,12,3,2,4
    Premier tri, sur le premier indice :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Mod1,12,1,4,7,8
    Mod6,8,3,1,1,5
    Mod5,6,2,2,1,6
    Mod7,6,4,2,1,5
    Mod8,5,2,1,3,5
    Mod2,4,1,2,6,7
    Mod3,4,1,1,5,2
    Mod4,1,3,2,4,6
    Mod9,1,5,2,3,4
    Mod10,1,6,3,2,4
    Mod11,1,12,3,2,4
    On affecte des rangs à cet indice :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Mod1,1,1,4,7,8
    Mod6,2,3,1,1,5
    Mod5,3,2,2,1,6
    Mod7,3,4,2,1,5
    Mod8,4,2,1,3,5
    Mod2,5,1,2,6,7
    Mod3,5,1,1,5,2
    Mod4,6,3,2,4,6
    Mod9,6,5,2,3,4
    Mod10,6,6,3,2,4
    Mod11,6,12,3,2,4
    Ensuite, nous poursuivons avec le 2nd indice (tri décroissant) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Mod11,6,12,3,2,4
    Mod10,6,6,3,2,4
    Mod9,6,5,2,3,4
    Mod7,3,4,2,1,5
    Mod6,2,3,1,1,5
    Mod4,6,3,2,4,6
    Mod5,3,2,2,1,6
    Mod8,4,2,1,3,5
    Mod1,1,1,4,7,8
    Mod2,5,1,2,6,7
    Mod3,5,1,1,5,2
    Puis affectation des rangs sur ce 2nd indice :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Mod11,6,1,3,2,4
    Mod10,6,2,3,2,4
    Mod9,6,3,2,3,4
    Mod7,3,4,2,1,5
    Mod6,2,5,1,1,5
    Mod4,6,5,2,4,6
    Mod5,3,6,2,1,6
    Mod8,4,6,1,3,5
    Mod1,1,7,4,7,8
    Mod2,5,7,2,6,7
    Mod3,5,7,1,5,2
    etc.
    On poursuit les tris et l'affectation de rangs pour obtenir le tableau final :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Mod1,1,7,1,1,1
    Mod2,5,7,3,2,2
    Mod4,6,5,3,4,3
    Mod5,3,6,3,7,3
    Mod8,4,6,4,5,4
    Mod7,3,4,3,7,4
    Mod6,2,5,4,7,4
    Mod9,6,3,3,5,5
    Mod11,6,1,2,6,5
    Mod10,6,2,2,6,5
    Mod3,5,7,4,3,6
    Qu'on peut (accessoire) trier par ordre alphabétique (colonne 1) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Mod1,1,7,1,1,1
    Mod2,5,7,3,2,2
    Mod3,5,7,4,3,6
    Mod4,6,5,3,4,3
    Mod5,3,6,3,7,3
    Mod6,2,5,4,7,4
    Mod7,3,4,3,7,4
    Mod8,4,6,4,5,4
    Mod9,6,3,3,5,5
    Mod10,6,2,2,6,5
    Mod11,6,1,2,6,5
    .... j'avoue que ce n'est pas le plus simple.
    Je poursuis dans un second message .

  10. #10
    Membre à l'essai
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 37
    Points : 12
    Points
    12
    Par défaut
    Merci beaucoup Deneteth et Philou pour vos scripts que je vais regarder de près .

    A l'exécution, il semble que Philou soit vraiment très proche de la solution parfaite . C'est minime, mais j'ai changé "my $rang = 0;" en "my $rang = 1;", afin de partir du rang 1.

    Quoi qu'il en soit, ce que vous codez est bien au dessus de mon niveau : on dirait un langage différent A tel point que j'ai du mal à comprendre (j'ai un peu honte là... ).

    Deux point restent donc encore obscures afin obtenir vraiment ce que je veux à partir du script de Philou, mais je ne sais pas si vous accepteriez de m'aider encore s'il vous plaît ?

    * Comment peut-on s'y prendre pour écrire le contenu de $out dans un fichier (problème de syntaxe = aucune idée de comment il faut faire) ? Habituellement, je me satisfait de choses type :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    open(SORTIE, $mode, "test.txt") or die("open: $!");
    	print SORTIE @out;
    close (SORTIE);
    * Comment faire en sorte que deux valeurs identiques prennent un même rang s'il vous plaît ?

    Honnêtement, c'est tellement plus complexe que ce que je fais d'habitude en unidimensionnel que je m'y perds un peu (et ce n'est pas de la «*feignantise*», je vous assure).
    Désolé encore pour ce dérangement et encore merci, vraiment, pour votre aide très précieuse .

    Cordialement.

  11. #11
    Membre à l'essai
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 37
    Points : 12
    Points
    12
    Par défaut
    Bon, après quelques essais, j'ai finalement compris comment résoudre le point 1 (*) : i.e. écrire le résultat dans un fichier.

    J'ai tout bêtement ouvert le fichier de sortie, puis j'ai changé les lignes de print en :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    print SORTIE join ",", map { shift @{$_} } @$array;
    print SORTIE "\n";
    Je me sens bête...
    Merci encore pour tout ça . Il me reste encore à trouver comment attribuer un même rang à toutes les valeurs identiques... ça risque d'être moins simple.

  12. #12
    Membre à l'essai
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 37
    Points : 12
    Points
    12
    Par défaut
    Bonjour à tous,

    Après pas mal de tests, je n'ai toujours pas réussi à trouver la solution pour cette question des valeurs identiques... Je vois bien qu'il faut sans doute agir sur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    $new_col[$_->[1]] = $rang++ foreach @$col;
    et faire en sorte que le $rang++ devienne conditionnel (si valeurs égales, on met seulement $rang ; on incrémente pas). Malheureusement, comme je ne maîtrise pas la syntaxe pour ce type de manip, je n'y suis pas arrivé.
    J'ai tenté de mettre en place une boucle conditionnelle, type :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    foreach @$col
    {
    	if (@a == b) { $new_col[$_->[1]] = $rang; }
    	else { $new_col[$_->[1]] = $rang++; }
    }
    Mais a priori c'est du n'importe quoi mon truc là...
    Quelqu'un aurait une idée s'il vous plaît ? Ca me sortirait vraiment une épine du pied...
    En vous remerciant bien pour toute aide.

  13. #13
    Membre averti

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2011
    Messages
    184
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Janvier 2011
    Messages : 184
    Points : 322
    Points
    322
    Par défaut
    Quelque chose comme de ce genre te conviendrait-il ?
    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
     
    my @z = qw{ Mod1 12 1 4 7 8 };
    my @a = qw{ Mod2 4 1 2 6 7 };
    my @b = qw{ Mod3 4 1 1 5 2 };
    my @c = qw{ Mod4 1 3 2 4 6 };
    my @d = qw{ Mod5 6 2 2 1 6 };
    my @e = qw{ Mod6 8 3 1 1 5 };
    my @f = qw{ Mod7 6 4 2 1 5 };
    my @g = qw{ Mod8 5 2 1 3 5 };
    my @h = qw{ Mod9 1 5 2 3 4 };
    my @i = qw{ Mod10 1 6 3 2 4 };
    my @j = qw{ Mod11 1 12 3 2 4 };
     
    my @t = ( \@z, \@a, \@b, \@c, \@d, \@e, \@f, \@g, \@h, \@i, \@j );
     
    foreach my $col ( 1 .. 5 ) {
      my $top = 0;
      my $rang = 0;
      my $i;
      @t = sort { -($$a[ $col ] <=> $$b[ $col ]) } @t;
      map { $i = $$_[ $col ]; $$_[ $col ] = $top == $$_[ $col ] ? $rang : ++$rang; $top = $i   } @t;
    }
    foreach my $i (  @t ){
      print join( ", ",@$i ), "\n";
    }

  14. #14
    Membre à l'essai
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 37
    Points : 12
    Points
    12
    Par défaut
    Génial !!!! Merci beaucoup, vraiment, Dimitry.e, pour ton aide précieuse
    Cette fois, cela fonctionne parfaitement sur le tableau. Cependant, dans le cas de ton code, je n'arrive pas à faire quelque chose : partir de mon fichier initial (final.csv) et non pas d'un tableau en mémoire ; ce fichier initial possède la structure suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    Mod1,1,7,1,1,1
    Mod2,5,7,3,2,2
    Mod3,5,7,4,3,6
    Mod4,6,5,3,4,3
    Mod5,3,7,3,7,3
    Mod6,2,5,4,7,4
    Mod7,3,4,3,7,4
    Mod8,4,6,4,5,4
    Mod9,6,3,3,5,5
    Mod10,6,2,2,6,5
    Mod11,6,1,2,6,5
    J'ai modifié le code pour que cela fonctionne avec un fichier ; cela donne :

    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
     
    my @t;
    my @word;
    my $ligne;
    my $nbdoc; # nombre de colonnes
     
    open (FICH, "final.csv") || die ("pas de fichier TEI\n");
     
    while ($ligne = <FICH>)
    {
    	@word = '';
    	@word = split(/[,]/, $ligne);
    	$nbdoc = @word;
    	push (@t, \@word );	        # c'est ici que je me plante non ?
    }
    close (FICH);
     
    # fin chargement
     
    $nbdoc = $nbdoc-1;
     
    foreach my $col ( $nbdoc ) {
      my $top = 0;
      my $rang = 0;
      my $i;
      @t = sort { -($$a[ $col ] <=> $$b[ $col ]) } @t;
      map { $i = $$_[ $col ]; $$_[ $col ] = $top == $$_[ $col ] ? $rang : ++$rang; $top = $i   } @t;
    }
    foreach my $i (  @t ){
      print join( ",",@$i ), "\n";
    }
    Mais cela ne colle plus. Il semble que je ne recrée pas la même structure pour le tableau @t avec ce code, par rapport à celle que tu donnais dans le tient. Il ne me reste plus que ce problème à solutionner et ce sera 100% parfait... est-ce que tu aurais une idée de ce qui cloche dans mon code modifié s'il te plaît ? J'ai ajouté la variable $nbdoc afin de pouvoir travailler avec des tableaux de toutes tailles...

    Merci encore pour votre aide, à tous

  15. #15
    Membre averti

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2011
    Messages
    184
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Janvier 2011
    Messages : 184
    Points : 322
    Points
    322
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    foreach my $col ( 1 .. $nbdoc ) {

  16. #16
    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
    Pour coder la partie "rang de valeur égale", je suis parti sur un autre algorithme utilisant cette fois une table de hashage : la clé contient alors la valeur, et la valeur contient une liste d'indice de cette valeur dans le tableau d'origine.
    Ensuite, je trie ces clés, et pour chacune, j'affecte tous les indices du tableau d'origine pour cette clé à la valeur du rang courant.

    Pour écrire dans un fichier plutôt que sur la sortie standard, la fonction to_csv_by_col sait le faire d'origine, il suffit de lui donner en paramètre un nom de fichier. On peut faire de même avec from_csv_by_col. Par exemple, on pourrait spécifier les fichiers à lire et écrire sur la ligne de commande, et fournir $ARGV[0] et $ARGV[1] à ces fonctions, comme ci-dessous :

    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
    #!/usr/bin/perl
     
    use strict;
    use warnings;
     
    sub from_csv_by_col {
      my ($file) = @_;
     
      my $cols = [];
      open my $F, "<", $file or die "Can't open $file for reading: $!";
      while (<$F>) {
        chomp;
        my @row = split /,/;
        map { push @{$cols->[$_]}, $row[$_] } 0 .. $#row;
      }
     
      return $cols;
    }
     
    sub to_csv_by_col {
      my ($array, $file) = @_;
     
      my $F;
      if (defined $file) {
        open $F, ">", $file or die "Can't open $file for writing: $!";
      }
      $F //= *STDOUT;
     
      while (@{$array->[0]}) {
        print { $F } join ",", map { shift @{$_} } @$array;
        print { $F } "\n";
      }
    }
     
    my $in = from_csv_by_col($ARGV[0]);
     
    # On recopie la première colonne
    my $out = [ splice @$in, 0, 1 ];
     
    foreach my $col (@$in) {
      my $row_index = 0;
      my %col;
      push @{$col{$_}}, $row_index++ foreach @$col;
      my $rang = 1;
      my @new_col;
      foreach (sort { $b <=> $a } keys %col) {
        @new_col[@{$col{$_}}] = map $rang, @{$col{$_}};
        $rang++;
      }
      push @$out, [ @new_col ];
    }
     
    to_csv_by_col($out, $ARGV[1]);
    Si tu as d'autres questions, n'hésites pas un instant. Le fait que tu ne comprennes pas tout, en tant que débutant, est tout à fait normal. Je ne fais d'ailleurs jamais d'effort pour écrire un code "à la portée" du débutant (ce qui signifie souvent, "au style C"). En effet, il me parait important de mettre en avant les opérateurs et fonctions qui font toute la puissance du langage, et qui sont peu connues des autres langages procéduraux (mais plus courant pour les langages de script). En perl, ces constructions grammaticales sont par ailleurs assez naturelles, et faciles à comprendre. Les points les moins triviaux concernent l'usage des sygils (les caractères $, @, %, ...) et des références, mais on finit par s'y faire, même s'il faut parfois tâtonner.

    <HS>Je rêve ou tu as changé de pseudo ?</HS>

  17. #17
    Membre à l'essai
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 37
    Points : 12
    Points
    12
    Par défaut
    Merci ! Merci ! Merci !
    Tout marche parfaitement Philou. Merci à toi, merci à tous pour votre aide vraiment précieuse.

    Ce matin je suis un peu "dans le gas", mais je regarde précisément dans la journée pour tenter de comprendre vraiment l'ensemble des instructions. Je vais sans doute poser des questions : merci de ton offre généreuse Philou.

    C'est vraiment super chouette de votre part.

    <HS>Oui, oui, Philou, j'ai "changé" de pseudo. En fait, j'avais deux pseudos et j'ai demandé qu'ils soient regroupés en un seul, pour plus de clarté - d'autant plus que j'ai peu de posts -... ce que les modos ont sympathiquement acceptés de faire </HS>

  18. #18
    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
    Attention, j'ai édité le script dans mon message précédent, notamment pour corriger les fonctions de lecture et d'écriture de fichier csv qui comportaient des bugs.

Discussions similaires

  1. [XL-2007] Tri + Copier / Coller un peu spécial
    Par mikeactuaire dans le forum Macros et VBA Excel
    Réponses: 9
    Dernier message: 18/04/2012, 17h55
  2. Tri un peu spéciale
    Par The eye dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 21/01/2008, 18h39
  3. AIDE sur Tableaux multidimensionnels
    Par orj30754 dans le forum C
    Réponses: 4
    Dernier message: 07/11/2006, 12h31
  4. [ADO - Access]Tri de valeurs alphanumériques un peu spécial
    Par portu dans le forum Bases de données
    Réponses: 8
    Dernier message: 12/04/2006, 10h08
  5. [Tableaux] tri sur tableaux
    Par pounie dans le forum Langage
    Réponses: 5
    Dernier message: 03/03/2006, 21h19

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