2012-02-07 162 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;