/ / Joindre des champs de différents fichiers en fonction d'une plage de nombres - bash, perl, awk, range

Jointure de champs de différents fichiers en fonction d'une plage de numéros - bash, perl, awk, range

J'ai trois fichiers dont la plupart sont similairesinformations, mais un unique déposé. Je veux les combiner en un seul fichier. Les fichiers ont en commun les colonnes avec l'en-tête hs et les colonnes avec l'en-tête range1 et range2. Les colonnes différentes sont celles étiquetées f1c, f2c et f3c. Je veux combiner les fichiers en fonction des régions qui se chevauchent dans range1 et range2 (les colonnes hs doivent également correspondre dans cette situation).

Son comme les gammes sont deux barres, bar1 (hs1) a350 sections et bar2 (hs2) a 700 sections. Les valeurs sous f1c f2c et f3c tiennent toutes dans une certaine quantité de ces sections sur chaque barre. Pour les valeurs qui correspondent à la même section, je veux les énumérer les unes à côté des autres.

N'importe quel type de solution en bash, awk ou perl fonctionnerait, je ne sais simplement pas comment je peux faire correspondre ces choses en fonction des plages.

Voici un exemple des fichiers

Premier format de fichier

hs  f1c range1 range2
hs1 p32 0      200
hs1 p31 200    300
hs1 p30 300    350
hs2 p32 0      300
hs2 p31 300    500
hs2 p30 500    700

Format du deuxième fichier

f2c       hs     range1 range2
DDX11L1   hs1    20     50
FAM41C    hs1    50     70
WASH7P    hs1    70     120
FAM138A   hs1    180    250
OR4F5     hs2    0      50
KLHL17    hs2    50     100
PLEKHN1   hs2    100    150
LOC729737 hs2    300    500
HES4      hs2    500    600
ISG15     hs2    600    700

Troisième format de fichier

hs  range1 range2 f3c
hs1 0      200    -1
hs1 200    350    -2
hs2 0      500    -1
hs2 500    700    -2

Voici un exemple de la sortie souhaitée (il y a un n sous f2c s'il n'y a pas de valeur dans file2 qui soit dans la plage)

hs    f1c   f2c      range1 range2 f3c
hs1   p32   n         0      20     -1   // From the 1st line of file3, and the 1st line of file1
hs1   p32   DDX11L1   20     50     -1   // From the 1st line of file1, 1st line of file2 and 1st line of file3
hs1   p32   FAM41C    50     70     -1   // From the 1st line of file1, 2nd line of file2 and 1st line of file3
hs1   p32   WASH7P    70     120    -1   // 1st line file1, 3rd line file2, first line file3
hs1   p32   n         120    180    -1   // 1st line file1, 1st line file3
hs1   p32   FAM13BA   180    200    -1   // 1st line file1, 4th line file2, 1st line file3
hs1   p31   FAM13BA   200    250.   -2   // 2nd line file1, 4th line file2, 2nd line file3
hs1   p31   n         250.   300    -2   // 2nd line file1, 2nd line file3
hs1   p30   n         300    350    -2   // 3rd line file1, 2nd line file3
hs2   p32   OR4FS     0      50     -1
hs2   p32   KLHL17    50     100    -1
hs2   p32   PLEKHN1   100    150    -1
hs2   p32   n         150    300    -1
hs2   p31   LOC729737 300    500    -1
hs2   p30   HES4      500    600    -2
hs2   p30   ISG15     600    700    -2

Je vous remercie

Réponses:

2 pour la réponse № 1

J'ai écrit ceci pour vous aider, mais vous devezcomprenez que votre question est inacceptable sur un site qui offre gratuitement une aide au diagnostic. Vous ne pouvez pas simplement formuler votre demande et attendre qu'une solution gratuite de haute qualité apparaisse. J'ai écrit une réponse uniquement parce que c'est un jour férié dans mon pays et que le problème m'a intéressé

J'ai mis beaucoup plus d'efforts pour créer ceque vous ne l'avez manifestement écrit dans votre question, et vous n'avez même pas pris la peine de répondre aux nombreuses questions que les gens vous ont posées dans les commentaires

use strict;
use warnings "all";
use autodie;

use Readonly::Tiny "Readonly";

Readonly my @FILES       => qw/ file1.txt file2.txt file3.txt /;
Readonly my $FORMAT      => "%-6s%-6s%-10s%-5d%-5d%dn";
Readonly my @OUTPUT      => qw/ hs f1c f2c range1 range2 f3c /;
Readonly my @KEY_COLUMNS => qw/ hs range1 range2 /;

my %data;   # All the data for each value of `hs`
my %bounds; # All the values of `range1` or `range2` for each value of `hs`
my %heads;  # All the headers found in any of the files

# From each file, read the header line and use the
# headers as keys for the data hashes representing each line
#
for my $file ( @FILES ) {

open my $fh, "<", $file; # Errors handled by `autodie`

my @head = split " ", <$fh>;
@heads{@head} = ();

while ( <$fh> ) {

next unless /S/;

my %row;
@row{@head} = split;

my ($hs, $r1, $r2) = @row{ @KEY_COLUMNS };
push @{ $data{$hs} }, %row;

++$bounds{$hs}{$_} for $r1, $r2;
}
}


# Change the `%bounds` hash values from
# hashes to sorted arrays of the boundary values
#
for ( values %bounds ) {

my @vals = sort {
my ($aa, $bb) = map { tr/0-9//cdr } $a, $b;
$aa <=> $bb;
} keys %$_;

$_ = @vals;
}

# Work through the `%bounds` hash
# printing a line of output for each range
#
for my $hs ( sort keys %bounds ) {

my $bounds = $bounds{$hs};
my $data   = $data{$hs};

for my $i ( 1 .. $#$bounds ) {

my ($r1, $r2) = map { $bounds->[$_] } $i-1, $i;

my @matches = grep {
$r1 >= $_->{range1} and $r2 <= $_->{range2}
} @$data;

my %row;

for my $match ( @matches ) {
@row{ keys %$match } = values %$match;
}

@row{ @KEY_COLUMNS } = ($hs, $r1, $r2); # Overwrite in the new key values

printf $FORMAT, map { $_ // "n" } @row{ @OUTPUT };
}
}

sortie

hs1   p32   n         0    20   -1
hs1   p32   DDX11L1   20   50   -1
hs1   p32   FAM41C    50   70   -1
hs1   p32   WASH7P    70   120  -1
hs1   p32   n         120  180  -1
hs1   p32   FAM138A   180  200  -1
hs1   p31   FAM138A   200  250  -2
hs1   p31   n         250  300  -2
hs1   p30   n         300  350  -2
hs2   p32   OR4F5     0    50   -1
hs2   p32   KLHL17    50   100  -1
hs2   p32   PLEKHN1   100  150  -1
hs2   p32   n         150  300  -1
hs2   p31   LOC729737 300  500  -1
hs2   p30   HES4      500  600  -2
hs2   p30   ISG15     600  700  -2