【问题标题】:In Perl, mapping between a reference file and a series of files在 Perl 中,参考文件和一系列文件之间的映射
【发布时间】:2015-07-14 15:07:27
【问题描述】:

我想在 Perl 中映射两个数据集。我有一个不变的数据集(参考 1),其他数据必须从一系列文件(1-20)中提取以匹配参考 1。

Ref1
ID1    ID2
1       HZ
1       HX
1       HY
2       C  
2       HZ
2       N

File 1
ID2    ID3
HA      5 
HB      4
HC      7
N       2

File 2
ID2    ID3
C      9
HZ     11
N      0

理想输出:

ID1 ID2 ID3 
1   HZ   5
1   HX   4 
1   HY   7
2   C    9
2   HZ   11
2   N    0

在 ref1 中 ID2 的第一个字母与 file1 中 ID2 的第一个字母之间发生匹配,直到匹配所有 ID1 条目,然后打开 file2 并与所有编号为 2 的 ID1 匹配。文件名的格式为number001.txt, number002.txt 等,所以可以从文件名中检索到 ID1。

我希望这是有道理的。我是 Perl 的初学者,这就是我目前所拥有的:

#!/usr/bin/perl
use strict;
use warnings;

my $ref1 = 'test.txt';
my $input_path = '/path/';

open my $fh, '<' $ref1 or die "Can't read $ref1: $!";
chomp (my @ref1 = <$fh>);

my %hash = @ref1;

my @filehandles;
for ($i=0; $i<20, $i++) {
    local *FILE;
    open(FILE, ">number$i.txt") or die $!;
    push(@filehandles, *FILE);
}

任何建议都会非常有帮助。

【问题讨论】:

    标签: perl


    【解决方案1】:

    这不是你想的那样:

    chomp (my @ref1 = <$fh>);
    my %hash = @ref1;
    

    在这里转置键/值并不神奇 - 所以你要做的是得到一个看起来像这样的哈希:

          '2       C  ' => '2       HZ',
          'ID1    ID2' => '1       HZ',
          '1       HX' => '1       HY',
          '2       N' => undef
    

    打赌那不是你想要的。

    我怀疑你可能想要的是:

        my %ref1;
        while ( <$input> ) {
            chomp;
            my ( $key, $value ) = split;
            push ( @{$ref1{$key}}, $value );
        }
        print Dumper \%ref1;
    

    您还将打开文件以在第二个循环中写入。你可能也不想这样做。

    我会选择类似的东西:

    #!/usr/bin/perl
    use strict;
    use warnings;
    
    use Data::Dumper;
    
    my $ref1       = 'ref1.txt';
    my $input_path = '/path/';
    
    open my $ref1_fh, '<', $ref1 or die "Can't read $ref1: $!";
    
    my %ref1;
    while (<$ref1_fh>) {
        chomp;
        next if m/ID/;
        my ( $key, $value ) = split;
        my $zeropadded = sprintf( "%03d", $key );
        my ($firstletter) = ( $value =~ m/^(\w)/ );
        push( @{ $ref1{$zeropadded}{$firstletter} }, $value );
    
    }
    
    print Dumper \%ref1;
    
    print join( "\t", "ID1", "ID2", "ID3" ), "\n";
    foreach my $filename ( glob("number*.txt") ) {
        my ($ref_num) = ( $filename =~ m/number(\d+)/ );
        open( my $input, "<", $filename ) or warn $!;
        while (<$input>) {
            chomp;
            my ( $key, $value ) = split;
            my ($firstletter) = ( $key =~ m/^(\w)/ );
            if ( defined $ref1{$ref_num}{$firstletter}
                and @{ $ref1{$ref_num}{$firstletter} } )
            {
                my $refkey = pop( @{ $ref1{$ref_num}{$firstletter} } );
    
                print join( "\t", int $ref_num, $refkey, $value ), "\n";
            }
        }
        close($input);
    }
    

    我已将“ref”编号转换为填充零,因此它直接匹配文件名,因为您指定文件名是 number001.txt 匹配 ref1 中的 1

    我还将$ref1 的内容插入到数组哈希中,键入您要查找的第一个字母 - 弹出“查找”值直到为空。

    因此我们得到:

    ID1 ID2 ID3
    1   HY  5
    1   HX  4
    1   HZ  7
    2   C   9
    2   HZ  11
    2   N   0
    

    【讨论】:

    • 非常感谢!!我不确定如何实现键值对,但这很有意义。
    【解决方案2】:

    我假设您要打印test.txt 的所有行以及ID3 列,该列是通过number*.txt 的组合定义的。

    已编辑(我误解了问题):

    ##  Save test.txt for later
    my $ref = shift;
    
    ##  Parse number*.txt
    my %id23;
    /(\S).* (\S+)/ and
        push @{$id23{$1}}, $2
        while(<>);
    
    ##  Combine in print
    @ARGV = $ref;
    /(.+?) +((.)\S*)/
        and printf "%6s %6s %6s\n", 
            $1, $2, shift @{$id23{$3}}
        while(<>);
    

    使用test.txt 后跟number*.txt 作为参数运行脚本。

    【讨论】:

      猜你喜欢
      • 2011-02-01
      • 2018-07-14
      • 2020-08-16
      • 2012-11-29
      • 2018-06-15
      • 2021-05-05
      • 1970-01-01
      • 1970-01-01
      • 2011-07-30
      相关资源
      最近更新 更多