2014-02-10 51 views
1

我有一个包含这样的数据的两个文件:组合来自两个文件散列成单个文件

FILE1包含组编号(第一列)和它们的开关的另一组(第二列)的频率(第三列):

FILE1:

1 2 0.6 
2 1 0.6 
3 1 0.4 
1 3 0.4 
2 3 0.2 

等...

FILE2包含组编号(第一列)和它们发生的频率(第二列)。

FILE2:

1 0.9 
2 0.7 
3 0.5 

等等

我想使含FILE2与从FILE1这样每个开关的值另一个文件:

1 0.9 2 0.6 3 0.4 ... 
2 0.7 1 0.6 3 0.2 ... 

基本上,我希望第一列是组号,第二列是它出现的频率,然后是它们切换到的组以及那个开关的频率,然后下一个切换到同一行的所有p关键组,然后下一行 - 组2等

所以,我想在FILE1中读取,为每个组做一个数组的散列,其中键是组号,值是它们切换到的组以及该组的频率开关。我将为每个包含他们切换到的每个组的子阵列的组和每个组分配一个大阵列和频率。然后我想使用与第一个散列相同的密钥创建另一个散列,但使用FILE2中第一列的数字和FILE2第二列中的值。然后我将输出“hash2 key hash2 value hash1 whole array for that key”。这是使用Perl我尝试:

#!/usr/bin/perl -W 

$input1= $ARGV[0]; 
$input2 = $ARGV[1]; 
$output = $ARGV[2]; 

%switches=(); 

open (IN1, "$input1"); 
while (<IN1>) { 
@tmp = split (/\s+/, $_); 
chomp @tmp; 
$group = shift @tmp; 
$switches{$group} = [@tmp]; 

push (@{$switches{$group}}, [@tmp]); 

} 

close IN1; 

%groups=(); 

open (IN2, "$input2"); 
while (<IN2>) { 
chomp $_; 
($group, $pop) = split (/\s+/, $_); 
$groups{$group} = $pop; 
} 
close IN2; 

open (OUT, ">$output"); 

foreach $group (keys %groups) { 
    print OUT "$group $pop @{$switches{$group}}\n" 
} 

close OUT; 

我得到的输出包含类似:

1 0.1 2 0.1 ARRAY(0x100832330) 
2 0.3 5 0.2 ARRAY(0x1008325d0) 

所以基本上:

“组”,“最后一个频率号”,“最后一个组该组切换到“”最后一个开关频率“”没有像ARRAY(0x100832330)“

我假设我做错了,在FILE1中将所有开关推入阵列的散列并且在打印结束时也会在最后解除引用。

请帮忙, 谢谢!

+1

请始终*在您编写的每个Perl程序开始时使用strict和'warnings'。它可以为您节省很多简单的错误,尤其适用于您在寻求代码帮助时。 – Borodin

回答

0

您的%switches散列包含冗余信息;只需使用push即可。此外,你需要做更多的工作来打印你想要的东西。这里是你的代码最小的变化:

$input1= $ARGV[0]; 
$input2 = $ARGV[1]; 
$output = $ARGV[2]; 

%switches=(); 

open (IN1, "$input1"); 
while (<IN1>) { 
@tmp = split (/\s+/, $_); 
chomp @tmp; 
$group = shift @tmp; 

push (@{$switches{$group}}, [@tmp]); 

} 

close IN1; 

%groups=(); 

open (IN2, "$input2"); 
while (<IN2>) { 
chomp $_; 
($group, $pop) = split (/\s+/, $_); 
$groups{$group} = $pop; 
} 
close IN2; 

open (OUT, ">$output"); 

foreach $group (sort {$a <=> $b} keys %groups) { 
    print OUT "$group $groups{$group} "; 
    for my $aref (@{$switches{$group}}) { 
     print OUT "@{$aref}"; 
    } 
    print OUT "\n"; 
} 

close OUT; 


__END__ 


1 0.9 2 0.63 0.4 
2 0.7 1 0.63 0.2 
3 0.5 1 0.4 

参见perldoc perldscperldoc Data::Dumper

0

由于每一列代表的价值的东西,而不是一个数组,你应该存储在一个更详细的结构数据。你可以通过references in Perl来做到这一点。

引用是指向另一个数据结构的指针。例如,您可以将您的组存储在散列中。但是,不是每个散列值都包含一堆由空格分隔的数字,而是每个散列值代替指向一个包含该组数据点的数组。并且,该数组中的这些数据点中的每一个都指向,其密钥为SWITCH,它们代表它们的切换FREQ的频率。

请您谈谈作为第1组的第一个数据点的频率:

$data{1}->[0]->{FREQ}; 

这样,您就可以更轻松地操控您的数据 - 即使你只是重写到另一个平文件。您还可以使用Storable模块以保存其结构的方式写入数据。

#! /usr/bin/env perl 
# 
use strict; 
use feature qw(say); 
use autodie; 
use warnings; 
use Data::Dumper; 

use constant { 
    FILE1  => "file1.txt", 
    FILE2  => "file2.txt", 
}; 

my %data; # A hash of an array of hashes (superfun!) 

open my $fh1, "<", FILE1; 

while (my $line = <$fh1>) { 
    chomp $line; 
    my ($group, $switch, $frequency) = split /\s+/, $line; 
    if (not exists $data{$group}) { 
     $data{$group} = []; 
    } 
    push @{ $data{$group} }, { SWITCH => $switch, FREQ => $frequency }; 
} 
close $fh1; 

open my $fh2, "<", FILE2; 
while (my $line = <$fh2>) { 
    chomp $line; 
    my ($group, $frequency) = split /\s+/, $line; 
    if (not exists $data{$group}) { 
     $data{$group} = []; 
    } 
    push @{ $data{$group} }, { SWITCH => undef, FREQ => $frequency }; 
} 
close $fh2; 
say Dumper \%data; 

这会给你:

$VAR1 = { 
     '1' => [ 
       { 
        'SWITCH' => '2', 
        'FREQ' => '0.6' 
       }, 
       { 
        'SWITCH' => '3', 
        'FREQ' => '0.4' 
       }, 
       { 
        'SWITCH' => undef, 
        'FREQ' => '0.9' 
       } 
       ], 
     '3' => [ 
       { 
        'SWITCH' => '1', 
        'FREQ' => '0.4' 
       }, 
       { 
        'SWITCH' => undef, 
        'FREQ' => '0.5' 
       } 
       ], 
     '2' => [ 
       { 
        'SWITCH' => '1', 
        'FREQ' => '0.6' 
       }, 
       { 
        'SWITCH' => '3', 
        'FREQ' => '0.2' 
       }, 
       { 
        'SWITCH' => undef, 
        'FREQ' => '0.7' 
       } 
       ] 
     }; 
+0

请不要重复'split/\ s + /'。你想要的是'split'',或者,如果你正在分割'$ _',那么只需'split'是合适的。 – Borodin

+0

*“您应该将数据存储在更详细的结构中”*当OP使用数组“%switches”的数组的散列与另一个简单散列“%groups”时,这是一个奇怪的注释。 – Borodin

0

这会做你的需要。

我对缺乏分析表示歉意,但已晚了,我应该上床睡觉。

我希望这会有所帮助。

use strict; 
use warnings; 

my $fh; 
my %switches; 

open $fh, '<', 'file1.txt' or die $!; 
while (<$fh>) { 
    my ($origin, @switch) = split; 
    push @{ $switches{$origin} }, \@switch; 
} 

open $fh, '<', 'file2.txt' or die $!; 
while (<$fh>) { 
    my ($origin, $freq) = split; 
    my $switches = join ' ', map join(' ', @$_), @{ $switches{$origin} }; 
    print join(' ', $origin, $freq, $switches), "\n"; 
} 

输出

1 0.9 2 0.6 3 0.4 
2 0.7 1 0.6 3 0.2 
3 0.5 1 0.4 

更新

这是你自己的代码,产生类似的结果了固定的版本。主要问题是%switches数组数组中的值,所以您必须执行两个解除引用。我已经通过添加@switches来解决这个问题,它包含与当前%switches值相同的内容,但具有代替两元素数组的字符串。

我也加了use strictuse warnings,并正确地声明了所有的变量。 open调用已被更改为带有词法文件句柄的三参数open,因为它们应该是,并且现在正在检查它们是否成功。我已更改您的split来电,因为只有简单的裸机split,无需任何参数。我已经删除了您的@tmp,并使用正确的列表分配。哦,我已经将浪费的[@array]更改为简单的\@array(如果没有使用my来声明变量,这将无法工作)。

我仍然认为我的版本更好,如果只是因为它更短,而且您的打印组按随机顺序。

#!/usr/bin/perl 

use strict; 
use warnings; 

my ($input1, $input2, $output) = @ARGV; 

my %switches; 

open my $in1, '<', $input1 or die $!; 
while (<$in1>) { 
    my ($group, @switches) = split; 
    push @{ $switches{$group} }, \@switches; 
} 

close $in1; 

my %groups; 

open my $in2, '<', $input2 or die $!; 
while (<$in2>) { 
my ($group, $pop) = split; 
$groups{$group} = $pop; 
} 
close $in2; 

open my $out, '>', $output or die $!; 
for my $group (keys %groups) { 
    my $pop = $groups{$group}; 
    my @switches = map "@$_", @{ $switches{$group} }; 
    print $out "$group $pop @switches\n" 
} 
close $out or die $!; 
相关问题