luckysing has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks I have written this program to add the values of the hash for each of the unique keys like A,B,C.The problem is now I want to find the average of A,B,C,D which are 11.5,15.5,17,18.For this I assume I need to keep the count of the keys.How do I do it?
DATA: A,10 A,11 A,12 A,13 B,15 B,16 C,17 D,18
#!/usr/bin/perl use strict; use Data::Dumper; open DATA,"read"; my %sum; while (<DATA>) { next if ( /^ID/ || /^\s$/ ); my ($id, $value) = split( "," ); $sum{$id} = $sum{$id} + $value; } print Dumper \%sum;
output: $VAR1 = { 'A' => 46, 'D' => '18', 'C' => '17', 'B' => 31 };

Replies are listed 'Best First'.
Re: get the average of hash values?
by toolic (Bishop) on Jul 27, 2010 at 23:29 UTC
    One way is to store the data in a hash-of-hashes:
    use strict; use warnings; my %data; while (<DATA>) { chomp; my ($id, $value) = split /,/; $data{$id}{sum} += $value; $data{$id}{count}++; } for my $id (sort keys %data) { my $avg = $data{$id}{sum}/$data{$id}{count}; print "$id: sum=$data{$id}{sum} avg=$avg\n"; } __DATA__ A,10 A,11 A,12 A,13 B,15 B,16 C,17 D,18

    prints:

    A: sum=46 avg=11.5 B: sum=31 avg=15.5 C: sum=17 avg=17 D: sum=18 avg=18

      Or you could do a hash of arrays (perldsc) and use List::Util to generate the required results:

      use strict; use warnings; use List::Util qw{sum min max}; my %data; while (<DATA>) { chomp; my ($id, $value) = split /,/; push @{ $data{$id} }, $value; # store values as HoA } for my $id (sort keys %data) { print "$id: " . summarise($data{$id}); } sub summarise{ my $arr = shift; return "max=" . max( @$arr ) . " min=" . min( @$arr ) . " sum=" . sum( @$arr ) . " mean=" . ( sum( @$arr )/scalar@$arr ) . "\n"; } __DATA__ A,10 A,11 A,12 A,13 B,15 B,16 C,17 D,18

      Gives:

      A: max=13 min=10 sum=46 mean=11.5 B: max=16 min=15 sum=31 mean=15.5 C: max=17 min=17 sum=17 mean=17 D: max=18 min=18 sum=18 mean=18

      NB: Code pretty much exactly the same as toolic's post... Just wanted to show TIMTOWTDI!

      Just a something something...
Re: get the average of hash values?
by Your Mother (Archbishop) on Jul 27, 2010 at 23:36 UTC

    This may not be particularly useful (too idiomatic) and it's missing some error checking but it was fun so...

    use List::Util qw( sum ); my $data = <<stuff; A,10 A,11 A,12 A,13 B,15 B,16 C,17 D,18 stuff my %stuff; for ( grep /[A-Z]/, split /\s+/, $data ) { my ( $letter, $number ) = split /,/; push @{$stuff{$letter}}, $number; } my $sum; for my $key ( keys %stuff ) { $sum += sum( @{$stuff{$key}} ) / @{$stuff{$key}}; } printf "Average of averages: %.2f\n", $sum / keys %stuff; __DATA__ Average of averages: 15.50
Re: get the average of hash values?
by JavaFan (Canon) on Jul 27, 2010 at 23:50 UTC
    Untested:
    my %data; while (<DATA>) { next if /^ID/ || /^\s$/; my ($id, $value) = split /,/; $data{$id}[0] += $value; $data{$id}[1] ++; } my %avg; while (my ($id, $info) = each %data) { $avg{$id} = $$info[0] / $$info [1]; }
    A reply falls below the community's threshold of quality. You may see it by logging in.