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 :

Différence entre deux fichiers


Sujet :

Langage Perl

  1. #1
    Membre éprouvé
    Avatar de Celelibi
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    1 087
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 1 087
    Points : 1 122
    Points
    1 122
    Par défaut Différence entre deux fichiers
    Bonjour,

    J'ai deux fichiers A et B et je voudrais récupérer toutes les lignes de A qui ne sont pas dans B.
    Le problème est assez simple à priori, mais pourtant je ne trouve pas de moyen plus simple que ça pour le faire :

    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
    open A, "<", "A";
    open B, "<", "B";
     
    my $a;
    my $b;
     
    $a = <A>;
    $b = <B>;
     
    while ($a && $b) {
      print $a if ($b gt $a);
      if ($a lt $b)
        $a = <A>;
      elseif ($a gt $b)
        $b = <B>;
      elseif ($a eq $b) {
        $a = <A>;
        $b = <B>;
      }
    }
    J'ai pas testé mais ça doit être ça (quoi que... si on arrive à la fin de B avant A).
    Ça suppose que les listes soient triés et sans doublons.

    Bref, je me demande juste si il n'y a pas un moyen plus simple de faire ça.

    Merci d'avance.
    Les vaches ne peuvent PAS voler, quoi qu'elles aient pu vous raconter.

  2. #2
    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
    A part les petites erreurs, il n'y a pas de procédé plus rapide, sachant que les deux fichiers sont déjà triés.
    Maintenant il y a une technique plus courte à écrire, et qui marche pour des fichiers quelconques :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    open my $filter, '<', 'B' or die "$!\n";
    my %h;
    @h{<$filter>} = ();
     
    open my $data, '<', 'A' or die "$!\n";
    print (grep {not exists $h{$_}} <$data>);
    Pour cette méthode, il ne faut pas que les fichiers soient trop gros, bien qu'on puisse s'accomoder d'un fichier "data" très gros, pourvu que le filtre soit de taille raisonnable (limite vers les millions de lignes, dépendante de la taille de la RAM), et qu'on remplace le grep par une boucle while().
    --
    Jedaï

  3. #3
    Membre éprouvé
    Avatar de Celelibi
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    1 087
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 1 087
    Points : 1 122
    Points
    1 122
    Par défaut
    Québecois ou insomniaque ?

    C'est une technique très intéressante, j'étais loin d'y penser.
    J'étais plutôt parti sur quelque chose qu'on écrirait ainsi en php :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    $a = file("A");
    $b = file("B");
    $c = array_diff($a, $b);
    Ce code php charge les fichiers A et B lignes par ligne dans les tableaux $a et $b, puis array_diff fait tout le boulot.

    Ça m'étonnerait qu'il n'y ait pas de syntaxe équivalente en perl, car si je ne m'abuse perl à pour vocation principale le traitement de fichiers texte.


    Edit : Je l'ai pas précisé, mais en fait je cherche à apprendre à coder réellement en perl, et non en perl C-isé.
    Les vaches ne peuvent PAS voler, quoi qu'elles aient pu vous raconter.

  4. #4
    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
    C'est à dire que le core de Perl ne doit pas être aussi enflé que le core de PHP... Ce array_diff est facile à coder en deux lignes et pas très utilisé (il y a des modules comme Array, Set::Scalar ou Set::Light qui le propose).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    sub array_diff {
      my ($a, $b) = @_;
      my %h;
      @h{@$b} = ();
      return grep {not exists $h{$_}} @$a;
    }
    Il est très facile de faire union et intersection également :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    sub union {
      my( $a, $b ) = @_;
      my %h;
      return grep {not $h{$_}++} @$a, @$b;
    }
     
    sub intersection {
      my( $a, $b ) = @_;
      my %h;
      return grep {$h{$_}++ == 1} @$a, @$b;
    }
    --
    Jedaï

  5. #5
    Membre éprouvé
    Avatar de Celelibi
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    1 087
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 1 087
    Points : 1 122
    Points
    1 122
    Par défaut
    Héhé, merci Jedai. J'ai cherché un peu les modules avec les noms que tu as donné, et voilà ce que ça donne.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    use Tie::File;
    use Set::Object;
     
    tie my @A, "Tie::File", "A";
    tie my @B, "Tie::File", "B";
     
    my $a = Set::Object->new(@A);
    $a->remove(@B);
    C'est un peu plus long que ce que tu avais proposé au début, mais je trouve que ça fait moins bidouille.

    Mais je regrette quand même que la procédure pour mettre un fichier dans un tableau soit pas plus simple.
    Et puis j'aurais bien utilisé Set::Light, mais je n'ai trouvé que Set::Object dans les packages debian.

    En tout cas merci pour tout.
    Les vaches ne peuvent PAS voler, quoi qu'elles aient pu vous raconter.

Discussions similaires

  1. Différence entre deux fichiers
    Par redkan dans le forum Shell et commandes GNU
    Réponses: 5
    Dernier message: 10/12/2013, 16h07
  2. Réponses: 9
    Dernier message: 12/07/2011, 18h25
  3. Outils sur les différences entre deux fichiers XML
    Par Community Management dans le forum XML/XSL et SOAP
    Réponses: 19
    Dernier message: 21/07/2008, 16h21
  4. Réponses: 4
    Dernier message: 16/04/2008, 12h12
  5. relever différences entre deux fichiers php
    Par midiweb dans le forum EDI, CMS, Outils, Scripts et API
    Réponses: 1
    Dernier message: 04/03/2008, 10h34

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