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

If i have data of format

name, amount

john, 100

john, 200

barry, 300

barry 200

how would i represent this data so i could iterate over the names and add the values so i would get output

john, 300

barry, 500

I have written code which will see if the names occur more than once but i can't work out how to sum the values for the names that appear more than once. I am very new to perl and know that a hash is required but hashes seem incompatible with my brain. I would appreciate it if someone could help with a simple explanation.

my %seen ; open(DATA, "<", "names.txt") or die "cannot open names.txt" ; while (<DATA>) { $line = $_ ; @array = split(/,/ , $line ) ; $name = $array[0] ; $amount = $array[1]; $seen{$name}++; if ( $seen{$name} > 1 ) { print "$name occurs more than onc +e" ; }

Replies are listed 'Best First'.
Re: adding values of element
by NetWallah (Canon) on Jan 22, 2015 at 01:49 UTC
    Try this one-liner:
    perl -anF/[\\s,]+/ -e '$tot{$F[0]}+=$F[1]}{print qq|$tot{$_}\t$_\n| fo +r sort keys %tot' <YOUR-FILE-NAME>
    Note the extra "\" for the shell (Linux assumed).

            "You're only given one little spark of madness. You mustn't lose it."         - Robin Williams

Re: adding values of element
by Anonymous Monk on Jan 21, 2015 at 22:51 UTC
    my $name = 'bob'; my $amount = 110; $sum{ $name } += $amount; ## sum of bob is increasing $amount = 100; $sum{ $name } += $amount; ## sum of bob is increasing $amount = 10; $sum{ $name } += $amount; ## sum of bob is increasing $amount = -100; $sum{ $name } += $amount; ## sum of bob is decreasing

      Thanks for replying.

      What i want to do is read each line of the file and get the name and the amount. then read the next line and if the name exists, add the amount.

      i could write a very long winded loop to get the unique name elements then for each of them add the amount per line but i am sure there is a better way to do this.

        Just read each line, remove the line terminator (chomp) then split name and value and add value to the appropriate hash element.

        $ perl -Mstrict -Mwarnings -MData::Dumper -E ' open my $dataFH, q{<}, \ <<EOF or die $!; john, 100 barry, 300 john, 200 mary, 150 barry, 200 EOF my %names; while ( <$dataFH> ) { chomp; my( $name, $value ) = split m{\s*,\s*}; $names{ $name } += $value; } print Data::Dumper->Dumpxs( [ \ %names ], [ qw{ *names } ] );' %names = ( 'john' => 300, 'barry' => 500, 'mary' => 150 ); $

        I hope this is helpful but ask further if you need more explanation.

        Cheers,

        JohnGG

        Hi, johngg beat me to it, but, I would have said, you could just rename %uniq to %sum and do "increasing/decreasing" inside the loop

        You got tricked by your choice of variable name, see Re^4: adding values of element, so I just wanted to emphasize that for you