我有两个类似的'表格式'文本文件,每个文件长达数百万条。在inputfile1中,唯一标识符是两个其他列中的值的合并(它们都不是唯一的标识符)。在inputfile2中,唯一标识符是两个字母,后跟一个随机的四位数字。
如何将inputfile1中的唯一标识符替换为inputfile2中相应的唯一标识符?第一个表中的所有记录都存在于第二个表中,但不是相反。以下是文件的玩具示例。
输入文件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
我的临时计划是:
我或许可以在R中做到这一点,但数据庞大而且复杂,我想知道bash或perl中是否存在某种方式。任何正确方向的提示都会很好。
答案 0 :(得分: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