2012-02-07 190 views
3

不知道這甚至正確的標題爲這個問題,因爲我是新來的Perl,但我有興趣2列的文本文件:如何基於來自不同哈希鍵的哈希值來對哈希值進行求和?

AB  Volume 
100  280 
137  250 
150  375 
100  100 
100  600 
137  200 

而且我想基於AB總結卷#,所得到的輸出是

AB  Instances  Volume 
100 3    980 
137 2    450 
150 1    375 

所有我所做的到現在是在輸出文件中顯示不同的AB公司,但我掙扎着爬卷數的總和。

$isAB{$AB} = 1; 
$isVolume{$Volume} =1; 
$numAB{$AB}++; 

print "AB\tInstances\tVolume\n"; 
for $AB (sort {$a<=>$b;} keys %numAB) { 
     print "$AB\t$numAB{$AB}\n"; 
} 

任何幫助將不勝感激!由於

+2

有語言「Perl」和「perl」解釋器,但沒有「PERL」。見[perlfaq1](http://perldoc.perl.org/perlfaq1.html) – JRFerguson 2012-02-07 16:24:50

回答

6

如何:

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

my %res; 
while(<DATA>) { 
    chomp; 
    my @fields = split; 
    $res{$fields[0]}{instance}++; 
    $res{$fields[0]}{volume} += $fields[1]; 
} 

foreach(sort {$a<=>$b} keys(%res)) { 
    say "$_\t$res{$_}{instance}\t$res{$_}{volume}"; 
} 

__DATA__ 
100     280 
137     250 
150     375 
100     100 
100     600 
137     200 

輸出:

100 3 980 
137 2 450 
150 1 375 
+0

更好地按數字排序...;) – pavel 2012-02-07 16:32:17

+1

好,雖然可以做得更具可讀性和更多自我記錄 – zgpmax 2012-02-07 16:33:27

+0

@pavel:你是對的,編輯答案。 – Toto 2012-02-07 16:44:12

1

添加另一個哈希以保持總和的軌道

$sumAB{$AB} += $isAB{$AB}; 

然後在打印循環

print "$AB\t$numAB{$AB}\t$sumAB{$AB}\n"; 
0

我建議使用record like data structure

#!/usr/bin/perl -w 
use strict; 
use warnings; 
use 5.010; 

my %res; 
while(<DATA>) {   
    (my $key, my $volume)= split; 
    $res{$key}->{QUANTITY}++; 
    $res{$key}->{VOLUME}+=$volume; 

} 

#use Data::Dumper; 
#print Dumper(%res); 

for my $key (sort {$a<=>$b} keys %res){ 
    my $quantity=$res{$key}->{QUANTITY}; 
    my $volume=$res{$key}->{VOLUME}; 
    say join("\t",$key, $quantity,$volume); 

} 


__DATA__ 
100  280 
137  250 
150  375 
100  100 
100  600 
137  200 
2

方式一:

內容infile

內容的 script.pl
AB  Volume 
100  280 
137  250 
150  375 
100  100 
100  600 
137  200 

use warnings; 
use strict; 
use List::Util qw(sum); 

## Check arguments. 
die qq[Usage: perl $0 <input-file>\n] unless @ARGV == 1; 

## Hash to save content of input file. 
my (%ab); 

while (<>) { 
    ## Split line. If number of fields is different from two, omit it 
    ## and read next one. 
    my @f = split; 
    next unless @f == 2; 

    ## In first line print header. 
    if ($. == 1) { 
     printf qq[%s\n], join qq[\t], $f[0], qq[Instances], $f[1]; 
     next; 
    } 

    ## Save fields of line. 
    push @{ $ab{ $f[0] } }, $f[1]; 
} 

## Print to output. 
for (sort { $a <=> $b } keys %ab) { 
    printf qq[%s\t%s\t%s\n], $_, scalar @{ $ab{ $_ } }, sum @{ $ab{ $_ } }; 
} 

運行腳本:

perl script.pl infile 

輸出:

AB  Instances  Volume 
100  3  980 
137  2  450 
150  1  375 
+2

+1,因爲它幾乎與我即將發佈的解決方案完全相同。你可以繞過'my @ hrs = split',<>'來解壓標題。然後用'splice @ hrs,1,0,「Instances」打印它們;說加入「\ t」,@ hrs;'。在最後一次打印中'join'也可以用來代替'printf'。 – TLP 2012-02-07 16:46:32

+0

@TLP:是的。你是對的。我會留下答案,但我理解你的觀點。謝謝。 – Birei 2012-02-07 17:01:58

0

歡迎的語言表達能力。對於這樣的事情,我建議List::Pairwise

my %sums; 
List::Pairwise::mapp { $sums{ $a } += $b } %numAB;