Как суммировать значения из хеша на основе ключей из другого хеша? - PullRequest
3 голосов
/ 07 февраля 2012

Не уверен, что это правильный заголовок для этого вопроса, так как я новичок в Perl, но у меня есть текстовый файл с двумя интересующими колонками:

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";
}

Любая помощь будет оценена! Спасибо

Ответы [ 5 ]

6 голосов
/ 07 февраля 2012

Как насчет:

#!/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
2 голосов
/ 07 февраля 2012

В одну сторону:

Содержимое infile:

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

Содержимое script.pl:

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
1 голос
/ 07 февраля 2012

Добавить еще один хеш для отслеживания суммы

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

затем в цикле печати

print "$AB\t$numAB{$AB}\t$sumAB{$AB}\n";
0 голосов
/ 08 февраля 2012

Добро пожаловать на выразительный язык. Для чего-то подобного я рекомендую List::Pairwise.

my %sums;
List::Pairwise::mapp { $sums{ $a } += $b } %numAB;
0 голосов
/ 07 февраля 2012

Я рекомендую использовать запись как структуру данных

#!/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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...