Génération de 2 fichiers basés sur deux colonnes dans un troisième fichier

J’essaie de préparer deux fichiers d’entrée en fonction des informations contenues dans un troisième fichier. Le fichier 1 correspond à l’échantillon1 et le fichier 2 à l’échantillon2. Ces deux fichiers ont des lignes avec des colonnes délimitées par des tabulations. La première colonne contient un identifiant unique et la deuxième colonne contient des informations.

Fichier 1

>ENT01 xxxxxxxxxxxxxx >ENT02 xyxyxyxyxyxy >ENT03 ththththththt 

..bientôt. De même, le fichier 2 contient

 >ENG012 ggggggggggggg >ENG098 ksksksksksks >ENG234 wewewewewew 

J’ai un fichier 3 qui contient deux colonnes correspondant chacune à l’identifiant du fichier 1 et du fichier 2

 >ENT01 >ENG78 >ENT02 >ENG098 >ENT02 >ENG012 >ENT02 >ENG234 >ENT03 >ENG012 

etc. Je veux préparer les fichiers d’entrée pour le fichier 1 et le fichier 2 en suivant l’ordre dans le fichier 3. Si une entrée est répétée dans le fichier 3 (ex ENT02), je souhaite répéter les informations pour cette entrée. La sortie attendue est Pour le fichier 1:

 >ENT01 xxxxxxxxxx >ENT02 xyxyxyxyxyxy >ENT02 xyxyxyxyxyx >ENT02 xyxyxyxyxyx >ENT03 ththththththth 

Et pour le fichier 2

 >ENG78 some info >ENG098 ksksksksks >ENG012 gggggggg >ENG234 wewewewewew >ENG012 gggggggg 

Toutes les entrées du fichier 1 et du fichier 2 sont uniques, mais pas dans le fichier 3. De plus, certaines entrées de fichier3 dans l’une ou l’autre colonne ne sont pas présentes dans le fichier 1 ou le fichier 2. La logique actuelle est la suivante: une intersection d’identifiants de la colonne 1 dans les deux fichiers 1 et 2 avec les colonnes respectives dans le fichier 3, en les stockant sous forme de liste et en utilisant cette liste pour comparer séparément les fichiers 1 et 2. Je travaille avec les lignes suivantes

awk 'FNR==NR{a[$1]=$0;next};{print a[$1]}' file1 intersectlist

grep -v -x -f idsnotfoundinfile1 file3

Je ne suis pas en mesure d’obtenir le bon résultat car je pense qu’à un moment donné, il est sortingé et que seules les valeurs uniq sont imprimées. Est-ce que quelqu’un peut m’aider s’il vous plait?

Vous devez lire et mémoriser les 2 premiers fichiers dans une structure de données, puis pour le troisième fichier, générer 2 nouveaux fichiers:

 $ awk -F'\t' -v OFS='\t' ' FNR == 1 {file_num++} file_num == 1 || file_num == 2 {data[file_num,$1] = $2; next} function value(str) { return str ? str : "some info" } { for (i=1; i<=2; i++) { print $i, value(data[i,$i]) > ARGV[i] ".new" } } ' file1 file2 file3 $ cat file1.new >ENT01 xxxxxxxxxxxxxx >ENT02 xyxyxyxyxyxy >ENT02 xyxyxyxyxyxy >ENT02 xyxyxyxyxyxy >ENT03 ththththththt $ cat file2.new >ENG78 some info >ENG098 ksksksksksks >ENG012 ggggggggggggg >ENG234 wewewewewew >ENG012 ggggggggggggg 

Les fichiers 1 et 2 doivent d’abord être lus pour que vous puissiez trouver leurs lignes avec des identificateurs à partir du fichier 3. Comme les identificateurs de ces fichiers sont uniques, vous pouvez créer un hachage pour chaque fichier, avec des identificateurs comme clés.

Traitez ensuite le fichier 3 ligne par ligne, où chaque identifiant de la ligne récupère sa valeur du hachage du fichier approprié et écrivez les lignes correspondantes dans les nouveaux fichiers 1 et 2.

 use warnings; use ssortingct; use feature 'say'; use Path::Tiny; my ($file1, $file2, $file3) = qw(File1.txt File2.txt File3.txt); my ($fileout1, $fileout2) = map { $_ . 'new' } ($file1, $file2); my %file1 = map { split } path($file1)->lines; my %file2 = map { split } path($file2)->lines; my ($ofh1, $ofh2) = map { path($_)->openw } ($fileout1, $fileout2); open my $fh, '<', $file3 or die "Can't open $file3: $!"; while (<$fh>) { my ($f1, $f2) = split; say $ofh1 "$f1\t", $file1{$f1} // 'some info'; #/ see text say $ofh2 "$f2\t", $file2{$f2} // 'some info'; } close $_ for $ofh1, $ofh2, $fh; 

Cela produit la sortie correcte basée sur des fragments de fichiers d’entrée fournis.

J’utilise Path :: Tiny ici pour sa concision. Sa méthode des lines renvoie toutes les lignes, et dans le bloc de la carte , chacune est divisée par espace par défaut. La liste de ces paires renvoyées par map est assignée à un hachage, chaque paire de chaînes successives formant une paire clé-valeur.

Plusieurs fichiers peuvent être ouverts dans une déclaration, et Path::Tiny rend à nouveau openw avec openw . Ses méthodes jettent l’exception ( die ) sur les erreurs, nous obtenons donc également une vérification des erreurs.

Si un identificateur dans le fichier 3 n’est pas trouvé dans le fichier 1/2, j’utilise carrément 'some info' comme indiqué dans la question, mais je m’attends à une solution plus complète pour un tel cas. Ensuite, le laconic // devrait être modifié pour prendre en charge un traitement supplémentaire (ou appeler un sous-titre à la place de 'some info' chaîne 'some info' ).

On suppose que les fichiers 1 et 2 ont toujours deux entrées sur une ligne.

Certains raccourcis sont pris, comme lire chaque fichier dans un hash dans une ligne. Veuillez développer le code selon vos besoins, avec les vérifications nécessaires.


Dans un tel cas, $file1{$f1} est undef donc l’opérateur // (défini ou) renvoie son argument côté droit. Une façon “correcte” est de tester if (exist $file1{$f1}) mais // fonctionne aussi bien.