-1

我有两个类似的“表格格式”文本文件,每个文件都有几百万条记录。在 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

我的临时计划是:

  1. 以 input1 的样式为 input2 生成额外的标识符(简单)
  2. 从 input2 中过滤掉不出现 input1 的行(hardish)
  3. 然后粘贴来自 input1 的数据(简单)

我也许可以在 R 中做到这一点,但数据又大又复杂,我想知道 bash 或 perl 中是否有办法。任何正确方向的提示都会很好。

4

1 回答 1

1

根据我的评论,这应该对您有用,假设GrpLen值在两个文件中的顺序相同

本质上,它从第一个文件中读取一行,然后从第二个文件中读取,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
于 2015-10-10T05:32:51.707 回答