我想在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);
}
任何建议都会非常有用。
答案 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
作为参数运行脚本。