2014-02-10 50 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 $!; 
相關問題