在Perl中,参考文件和一系列文件之间的映射

时间:2015-05-05 03:00:46

标签: perl

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

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);
}

任何建议都会非常有用。

2 个答案:

答案 0 :(得分:4)

这不符合您的想法:

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中指定的文件名是1匹配ref1

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

所以我们得到:

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

答案 1 :(得分:1)

我假设您要打印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作为参数运行脚本。