bash 根据唯一 ID 合并表
bash merging tables on unique id
我有两个相似的 'table format' 文本文件,每个都有几百万条记录。在 inputfile1 中,唯一标识符是其他两个列中值的合并(它们本身都不是唯一标识符)。在inputfile2中,唯一标识符是两个字母后跟一个随机的四位数字。
如何将 inputfile1 中的唯一标识符替换为 inputfile2 中相应的唯一标识符?第一个 table 中的所有记录都出现在第二个中,但反之则不然。以下是文件的玩具示例。
输入文件 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
我的临时计划是:
- 以 input1 的样式(简单)为 input2 生成额外的标识符
- 过滤掉 input2 中不出现 input1 的行(困难)
- 然后坚持输入 1 的数据(简单)
我也许可以在 R 中做到这一点,但数据又大又复杂,我想知道在 bash 或 perl 中是否有办法。任何正确方向的提示都会很好。
这应该对你有用,假设 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
更新
这是另一个相同的版本,除了它根据第一个文件中 headers 列的间距构建 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
我有两个相似的 'table format' 文本文件,每个都有几百万条记录。在 inputfile1 中,唯一标识符是其他两个列中值的合并(它们本身都不是唯一标识符)。在inputfile2中,唯一标识符是两个字母后跟一个随机的四位数字。
如何将 inputfile1 中的唯一标识符替换为 inputfile2 中相应的唯一标识符?第一个 table 中的所有记录都出现在第二个中,但反之则不然。以下是文件的玩具示例。
输入文件 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
我的临时计划是:
- 以 input1 的样式(简单)为 input2 生成额外的标识符
- 过滤掉 input2 中不出现 input1 的行(困难)
- 然后坚持输入 1 的数据(简单)
我也许可以在 R 中做到这一点,但数据又大又复杂,我想知道在 bash 或 perl 中是否有办法。任何正确方向的提示都会很好。
这应该对你有用,假设 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
更新
这是另一个相同的版本,除了它根据第一个文件中 headers 列的间距构建 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