/ / Łączenie pól z różnych plików na podstawie zakresu liczb - bash, perl, awk, zakres

Łączenie pól z różnych plików na podstawie zakresu liczb - bash, perl, awk, zakres

Mam trzy pliki w większości podobneinformacje, ale jeden unikalny złożony. Chcę połączyć je w jeden plik. Pliki mają wspólne kolumny z nagłówkiem hs i kolumnami z zakresem nagłówka1 i zakresu2. Kolumny, które są różne, to te oznaczone f1c, f2c i f3c. Chcę połączyć pliki na podstawie tego, które regiony zachodzą na siebie w zakresie1 i zakresu2 (kolumny hs muszą również pasować w tej sytuacji).

Podobnie jak zakresy to dwa słupki, bar1 (hs1) ma350 sekcji i bar2 (hs2) ma 700 sekcji. Wszystkie wartości w f1c f2c i f3c mieszczą się w określonej ilości tych sekcji na każdym pasku. Dla wartości, które mieszczą się w tej samej sekcji, chcę wymienić je obok siebie.

Jakiekolwiek rozwiązanie w bashu, awk lub perlu zadziałałoby, po prostu nie jestem pewien, jak mogę dopasować te rzeczy w oparciu o zakresy.

Oto przykład plików

Pierwszy format pliku

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

Drugi format pliku

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

Trzeci format pliku

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

Oto przykład pożądanego wyjścia (w f2c znajduje się n, jeśli nie ma wartości w pliku2, która mieści się w zakresie)

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

Dziękuję Ci

Odpowiedzi:

2 dla odpowiedzi № 1

Napisałem to, aby ci pomóc, ale musiszzrozum, że twoje pytanie jest nie do przyjęcia na stronie, która oferuje pomoc diagnostyczną za darmo. Możesz po prostu postawić swoje wymagania i czekać na pojawienie się wysokiej jakości bezpłatnego rozwiązania. Napisałem odpowiedź tylko dlatego, że jest to dzień wolny od pracy w moim kraju i problem mnie zainteresował

Włożyłem dużo więcej wysiłku w stworzenie tegoniż oczywiście napisałeś pytanie, a nawet nie zadałeś sobie trudu, by odpowiedzieć na kilka pytań, które ludzie zadawali ci w komentarzach

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 };
}
}

wydajność

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