Таблицы слияния 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
Мой предварительный план:
- Генерация дополнительных идентификаторов для input2, в стиле input1 (легко)
- Отфильтровать строки из input2, которые не встречаются, input1 (hardish)
- Затем вставьте данные из 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