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 :

Réduction de liste


Sujet :

Langage Perl

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Apprenti bioinformatique
    Inscrit en
    Mars 2015
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Apprenti bioinformatique
    Secteur : Santé

    Informations forums :
    Inscription : Mars 2015
    Messages : 17
    Par défaut Réduction de liste
    Bonjour,

    je n'utilise pas Perl régulièrement, et ça se sent quand j'en ai besoin.
    Mon problème est simple, et la solution doit l'être tout autant. Mais...

    Je dispose d'une liste de chaîne de caractères de la forme suivante : id;nombre , id;nombre ...
    Le ; vient de la concaténation que j'ai fait des éléments avant de les mettre dans la liste, mais peu importe. Cela sera plus clair dans un tableau :

    id1 3.2
    id1 12.7
    id1 2
    id2 1.2
    id2 6.5
    id3 7.8
    id3 0.5
    id4 15.6
    id1 1.5
    id1 9.3

    L'idée est la suivante, je voudrais, pour chaque groupe d'id identique, ne conserver que la plus haute valeur.
    Sachant qu'il y a plusieurs groupe d'id au nom similaire (ici id1), je veux conserver la plus haute valeur de chacun de ces groupes de même nom.
    Cela donnerai :

    id1 12.7
    id2 6.5
    id3 7.8
    id4 15.6
    id1 9.3

    Pour ce qui est de récupérer le maximum, la fonction max du package List::Util fait très bien l'affaire.
    Ok, je viens de me rendre compte que sous la forme id;nombre la fonction max ne fait que me renvoyer le dernier élément de la liste, mais dans le sens nombre;id, il renvoie bien la plus haute valeur. Soit.

    Le fait est que je ne vois pas bien comment isoler chaque groupe pour récupérer le maximum à chaque fois.

    Je me prend la tête avec des boucles, mais comment conserver la valeur de l'itération précédente ?

    En fait, cette liste est créée en extrayant deux éléments de chaque ligne d'un csv. Je suppose que le filtre pourrait se faire à ce niveau, mais ça ne change pas le problème de la valeur de l'itération précédente.

    Bref, je patauge. Si vous avez une idée, ou un bout de piste, je suis preneur !
    Merci !

  2. #2
    Membre éprouvé
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Juillet 2014
    Messages
    84
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : Conseil

    Informations forums :
    Inscription : Juillet 2014
    Messages : 84
    Par défaut
    Un bout de code à l'arrache (qui fonctionne chez moi )

    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
    #!/usr/bin/perl -W
    use strict;
    use warnings;
    use Data::Dumper;
    use List::Util qw(max);
     
    my $filename = "data.csv";
     
    my %hashIdVal = ();
    open ( IN, "<$filename") || die ("Erreur d'ouverture");
     
    foreach (<IN>){
    	chomp;
    	my ($id, $val) = split( /;/, $_ );
    	push( @{$hashIdVal{$id}}, $val);
    }
     
    #print Dumper( \%hashIdVal )."\n";
    foreach my $key (sort keys( %hashIdVal)){
     
    	my $maximum = max(@{$hashIdVal{$key}});
    	print "key :: $key\t Max :: $maximum\n";
    }
    close( IN );
    je lis le fichier, je splitte chaque ligne sur le caractère ';', je pousse chaque valeur dans un hash qui contient pour chaque clé un array,
    puis, pour chaque clé du hash trié par clé (le 'sort keys'), je cherche le maximum avec la fonction max et j'affiche le tout.

    Autre solution possible : calculer le max à la lecture de chaque ligne, toujours en utilisant le hash.

  3. #3
    Membre averti
    Homme Profil pro
    Apprenti bioinformatique
    Inscrit en
    Mars 2015
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Apprenti bioinformatique
    Secteur : Santé

    Informations forums :
    Inscription : Mars 2015
    Messages : 17
    Par défaut
    Bonjour,

    merci pour la réponse rapide !
    Et effectivement, ça fonctionne (les tables de hash, je me disais bien qu'il faudrait en passer par là, mais j'ai toujours du mal à les utiliser...).

    A un détail près, les deux groupes id1 sont confondus, puisque la clé est la même.
    Hors je voudrais pouvoir récupérer le maximum du premier ET du deuxième groupe id1. Comme sur mes tableaux du premier post.
    Comme un id1_1 et id1_2 en fait.

    Avec cette solution, il faudrait que je renomme au préalable les nouveaux groupes avec un nom identique à ceux déjà parcouru. Mais on revient au même problème je pense.
    Peut-être pourrais-je faire une liste de listes, et appliquer la fonction max sur chaque liste de cette liste. Le problème étant comment identifier chaque sous groupe, sans mélanger les groupes différents (de par leur positionnement dans le csv) mais de même id.

    En tout cas, je verrais ça demain.
    Merci encore !

  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 : 59
    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
    Par défaut
    Pour répondre à ton objection, il faudrait que tu spécifies comment on peut "objectivement" détecter le début d'un nouveau groupe... (ici, on pourrait supposer qu'un nouveau groupe démarre lorsque le numéro suivant le text "id" devient strictement inférieur au précédent, mais est-ce vraiment le cas ? et est-ce que tous les éléments de la colonne 1 seront toujours dans ce format ? Comment traiter id_9 et id_09 ? ...)

  5. #5
    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
    Billets dans le blog
    1
    Par défaut
    En supposant que les groupes sont ordonnés et que tout changement d'ID clôt l'affaire pour un groupe (et en supposant que les valeurs sont toujours positives), un bout de code vite fait sans tester:
    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
     
    #!/usr/bin/perl
    use strict;
    use warnings;
     
    my $filename = "text.txt";
    open my $IN, "<", $filename or die "Ouverture impossible de $filename : $!");
     
    my $old_id = "";
    my $first_line = <$IN>;
    my ($maxid, $maxval) = split /;/, $first_line; # initialisation  des max avec première ligne
    while (<$IN>) {
        my ($id, $val) = split /;/, $_;
        if ($id eq $old_id) {
            next unless $val > $maxval;
        } else {
            print "$maxid : $maxval \n";
        }
        $maxval = $val;
        $maxid = $id;
    }
    print "$maxid : $maxval \n"; # ne pas oublier le dernier max en fin de fichier
    close $IN;

  6. #6
    Membre chevronné 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
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Taisha:~/perl/forum $ echo "id1;3.2 , id1;12.7 , id1;2 , id2;1.2 , id2;6.5 , id3;7.8 , id3;0.5 , id4;15.6 , id1;1.5 , id1;9.3" > datain
    Taisha:~/perl/forum $ perl -E 'local $/ = q{,}; while (<>) { ($i,$n) = m/(\w+);([0-9.]+)/; if ($i ne $pi) { say "$pi:$m" if $pi; ($pi, $m) = ($i, $n) } else { $m = $n if $n > $m }} say "$pi:$m"' datain
    id1:12.7
    id2:6.5
    id3:7.8
    id4:15.6
    id1:9.3
    Taisha:~/perl/forum $
    update: je viens de voir la version de Lolo78, c'est le même principe. Principale différence, ici on se fonde sur le fait que $pi est initialement undef (donc d'une part différent de tout id dans le test if ($i ne $pi), et d'autre part faux dans le test if $pi ), ce qui permet d'éviter de lire séparément la première ligne.

Discussions similaires

  1. Réponses: 8
    Dernier message: 27/12/2009, 23h58
  2. [Bison] Liste des "décalage/réduction"
    Par minirop dans le forum Autres éditeurs
    Réponses: 10
    Dernier message: 25/04/2009, 12h19
  3. tri de liste chainée
    Par RezzA dans le forum C
    Réponses: 7
    Dernier message: 26/01/2003, 20h25
  4. Compter le nombre ligne listée (COUNT) ?
    Par StouffR dans le forum Langage SQL
    Réponses: 7
    Dernier message: 02/09/2002, 09h41
  5. Listes déroulantes liées entre elles
    Par denisC dans le forum Général JavaScript
    Réponses: 0
    Dernier message: 27/07/2002, 15h53

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