8
votes

Comment puis-je parcourir deux fichiers simultanément à Perl?

J'ai deux fichiers texte contenant des données colonnes de la variété position - de valeur , triée par position .

Voici un Exemple de premier fichier (fichier A ): xxx

Voici un exemple du deuxième fichier ( B ) : xxx

au lieu de lire l'un des deux fichiers dans une table de hachage, qui est prohibitif en raison de contraintes de mémoire, ce que je voudrais faire est de marcher sur deux fichiers simultanément, de la mode par étapes.

Qu'est-ce que cela signifie que je voudrais diffuser des lignes de A ou B et comparer position < / Code> Valeurs.

Si les deux positions sont égales, j'effectue un calcul sur les valeurs associées à cette position.

Sinon, si les positions ne sont pas égales, je passe à travers des lignes de fichier a ou fichier b jusqu'à ce que les positions soient égales (quand j'effectue à nouveau Mon calcul) ou j'atteint Eof des deux fichiers.

existe-t-il un moyen de le faire à Perl?


3 commentaires

Combien de lignes dans chaque fichier? Quelle est la contrainte de mémoire?


Qu'avez-vous essayé jusqu'à présent? Y a-t-il quelque chose de plus subtil que d'ouvrir les deux fichiers, de lire des lignes de chacun, etc.?


Création d'une table de hachage à plusieurs Go ou de la lecture de l'un des deux fichiers dans un tableau en mémoire n'est pas fonctionnel - je cherche à diffuser les deux fichiers, à l'aide de leur propriété triée pour entrer dans l'un ou l'autre des fichiers en fonction de la position actuelle.


4 Réponses :


2
votes

Pour boucle via des fichiers, vous pouvez utiliser le noyau Cravate :: Fichier module. Il représente un fichier texte régulier en tant que tableau.


0 commentaires

5
votes

Si les fichiers sont triés, entrez-les sur la base de laquelle une position inférieure.

pseudocode: xxx

Vous pouvez également utiliser rejoindre (1) pour isoler les lignes avec des positions communes et traiter à votre Loisirs.


0 commentaires

6
votes

ressemble à un problème que l'on pourrait probablement trébucher, par exemple des données de table de base de données avec des clés et des valeurs. Voici une implémentation de la pseudocode fournie par RJP.

#!/usr/bin/perl

use strict;
use warnings;

sub read_file_line {
  my $fh = shift;

  if ($fh and my $line = <$fh>) {
    chomp $line;
    return [ split(/\t/, $line) ];
  }
  return;
}

sub compute {
   # do something with the 2 values
}

open(my $f1, "file1");
open(my $f2, "file2");

my $pair1 = read_file_line($f1);
my $pair2 = read_file_line($f2);

while ($pair1 and $pair2) {
  if ($pair1->[0] < $pair2->[0]) {
    $pair1 = read_file_line($f1);
  } elsif ($pair2->[0] < $pair1->[0]) {
    $pair2 = read_file_line($f2);
  } else {
    compute($pair1->[1], $pair2->[1]);
    $pair1 = read_file_line($f1);
    $pair2 = read_file_line($f2);
  }
}

close($f1);
close($f2);


2 commentaires

On suppose qu'il y a un utiliser autodie là aussi pour vérifier ces ouvertures nues pour des erreurs. ;)


Cela a bien fonctionné comme un début, merci! Une complication est que le tandis que ($ paire1 et $ paire2) Le test fera la fin de la boucle dès que l'un des fichiers atteint EOF. Ma question, comme encadré, fait cela un non-question - cependant, je dois faire des choses avec les deux autres cas d'égalité des paires. J'ai donc modifié read_file_line pour renvoyer la ligne suivante ou la ligne actuelle, et je garde une paire de booléens pour vérifier si la ligne paire a changé. Au lieu de tester pour EOF, je testez si les deux lignes ont été inchangées en exécutant read_file_line . Si oui, je peux alors quitter en toute sécurité le pendant que boucle.



2
votes

Voici une solution rapide. Si les données des deux fichiers sont assez équivalentes (par exemple le même nombre de lignes), vous n'avez pas besoin de stocker dans des tables de hachage. Mais je pensais que ce serait utile au cas où les données sont brouillées.

Code: p>

open(f1, "<data1");
open(f2, "<data2");
# initialize hashes
%data1 = ();
%data2 = ();
while(($line1 = <f1>) and ($line2 = <f2>)){
     chomp($line1);
     chomp($line2);
     # split fields 1 and 2 into an array
     @LINE1 = split(/\t/, $line1);
     @LINE2 = split(/\t/, $line2);
     # store data into hashes
     $data1{$LINE1[0]} = $LINE1[1];
     $data2{$LINE2[0]} = $LINE2[1];
     # compare column 2
     if ($data1{$LINE2[0]} == $data2{$LINE1[0]}){
           # compute something
           $new_val = $data1{$LINE2[0]} + $data2{$LINE1[0]};
           print $LINE1[0] . "\t" . $new_val . "\n";
     } else {
           print $LINE1[0] . "\t" . $data1{$LINE1[0]} . "\n";
     }
}


2 commentaires

Bienvenue à Stackoverflow! Lorsque vous répondez aux questions, essayez de donner une brève explication de ce que vous avez fait, avec le code.


Merci pour le commentaire. Je suis nouveau, alors j'ai supposé que les commentaires dans le code suffiraient.