Таблицы слияния bash по уникальному идентификатору

У меня есть два похожих текстовых файла в формате таблицы, каждый из которых содержит несколько миллионов записей. Во входном файле1 уникальный идентификатор представляет собой объединение значений в двух других столбцах (ни один из которых не является уникальным идентификатором сам по себе). Во входном файле2 уникальный идентификатор состоит из двух букв, за которыми следует случайное четырехзначное число.

Как заменить уникальные идентификаторы во входном файле1 соответствующими уникальными идентификаторами во входном файле2? Все записи в первой таблице присутствуют во второй, хотя и не наоборот. Ниже приведены игрушечные примеры файлов.

Входной файл 1:

Grp Len ident   data
A   20  A_20    3k3bj52
A   102 A_102   3k32rf2
A   352 A_352   3w3bj52
B   60  B_60    3k3qwrg
B   42  B_42    3kerj52
C   89  C_89    3kftj55
C   445 C_445   fy5763b

Входной файл 2:

Grp Len ident
A   20  fz2525
A   102 fz5367
A   352 fz4678
A   356 fz1543
B   60  fz5732
B   11  fz2121
B   42  fz3563
C   89  fz8744
C   245 fz2653
C   445 fz2985
C   536 fz8983

Желаемый результат:

Grp Len ident   data
A   20  fz2525  3k3bj52
A   102 fz5367  3k32rf2
A   352 fz4678  3w3bj52
B   60  fz5732  3k3qwrg
B   42  fz3563  3kerj52
C   89  fz8744  3kftj55
C   445 fz2985  fy5763b

Мой предварительный план:

  1. Генерация дополнительных идентификаторов для input2, в стиле input1 (легко)
  2. Отфильтровать строки из input2, которые не встречаются, input1 (hardish)
  3. Затем вставьте данные из input1 (легко)

Я мог бы сделать это в R, но данные большие и сложные, и мне было интересно, есть ли способ в bash или perl. Любые советы в правильном направлении было бы хорошо.

1 ответ

Решение

Это должно работать для вас, предполагая, что Grp а также Len значения в том же порядке в обоих файлах, как в моем комментарии

По сути, он читает строку из первого файла, а затем читает из второго файла, образуя Grp_Len ключ от каждой записи, пока не найдет соответствующую запись. Тогда это просто вопрос создания новой выходной записи

use strict;
use warnings;

open my $f1, '<', 'file1.txt';
print scalar <$f1>;
open my $f2, '<', 'file2.txt';
<$f2>;

while ( <$f1> ) {

    my @f1 = split;

    my @f2;
    while () {
        @f2 = split ' ', <$f2>;
        last if join('_', @f2[0,1]) eq $f1[2];
    }

    print "@f2 $f1[3]\n";
}

выход

Grp Len ident   data
A 20 fz2525 3k3bj52
A 102 fz5367 3k32rf2
A 352 fz4678 3w3bj52
B 60 fz5732 3k3qwrg
B 42 fz3563 3kerj52
C 89 fz8744 3kftj55
C 445 fz2985 fy5763b



Обновить

Вот еще одна версия, которая идентична за исключением того, что она создает printf форматировать строку из интервала заголовков столбцов в первом файле. Это приводит к намного более аккуратному выходу

use strict;
use warnings;

open my $f1, '<', 'file1.txt';
my $head = <$f1>;
print $head;
my $format = create_format($head);

open my $f2, '<', 'file2.txt';
<$f2>;

while ( <$f1> ) {

    my @f1 = split;

    my @f2;
    while () {
        @f2 = split ' ', <$f2>;
        last if join('_', @f2[0,1]) eq $f1[2];
    }

    printf $format, @f2, $f1[3];
}

sub create_format {
    my ($head) = @_;
    my ($format, $pos);

    while ( $head =~ /\b\S/g ) {
        $format .= sprintf("%%-%ds", $-[0] - $pos) if defined $pos;
        $pos = $-[0];
    }

    $format . "%s\n";
}

выход

Grp Len ident   data
A   20  fz2525  3k3bj52
A   102 fz5367  3k32rf2
A   352 fz4678  3w3bj52
B   60  fz5732  3k3qwrg
B   42  fz3563  3kerj52
C   89  fz8744  3kftj55
C   445 fz2985  fy5763b
Другие вопросы по тегам