[Chicago-talk] Combine like hash elements

Joel Limardo joel.limardo at forwardphase.com
Mon Nov 23 13:46:21 PST 2015


I disagree that this should be put in a database unless you have sufficient
values to warrant that. If you are dealing with just a few dozen values
relying upon a database to essentially sort a hash is not very Perl-ish I
think. At any rate, here is a more verbose example that uses Data::Dumper.
The other examples provided before should be better, but I offer this
because you can debug it and see what is happening line by line:

use strict;
use Data::Dumper;
my $targetRef;
my $hashRef =
{
    '11' => {'AMOUNT' => '20.00','ID' => '11','NAME' => 'Lincoln Park'},
    '12' => {'AMOUNT' => '38.00','ID' => '12','NAME' => 'Bucktown'},
    '13' => {'AMOUNT' => '41.00','ID' => '11','NAME' => 'Lincoln Park'}
}; #ID on line 3 fixed to match first line id

foreach my $structId(keys %$hashRef)
{
    my $struct = $hashRef->{$structId};
    if (!$targetRef->{$struct->{'ID'}}){
    $targetRef->{$struct->{'ID'}} = {   'NAME'  => $struct->{'NAME'},
                                            'ID'    => $struct->{'ID'},
                                            'AMOUNT'=> $struct->{'AMOUNT'}
};
    } else {
    $targetRef->{$struct->{'ID'}}->{'AMOUNT'} +=
        $struct->{'AMOUNT'};
    }
}

print Dumper $targetRef;

1;

== produces ==

$VAR1 = {
          '12' => {
                    'ID' => '12',
                    'AMOUNT' => '38.00',
                    'NAME' => 'Bucktown'
                  },
          '11' => {
                    'NAME' => 'Lincoln Park',
                    'AMOUNT' => '61',
                    'ID' => '11'
                  }
        };


On Mon, Nov 23, 2015 at 12:55 PM, imran javaid <imranjj at gmail.com> wrote:

> You could also push the aggregation to the DB server and have it do the
> sum by name.
>
> On Mon, Nov 23, 2015 at 12:52 PM, <richard at rushlogistics.com> wrote:
>
>> Hello Everybody,
>>
>>
>>
>> Thank you for all the replies. The ID field did not need to be preserved.
>> However, I was having difficulty conceptualizing the manipulation of the
>> hash so I decided to use DBI->bind_colums instead and iterate throught the
>> values in a way that I found at least a bit more clear. Still working on
>> cleaning this up but this is at least the direction that I am going in.
>>
>>
>>
>> Thanks again for the help.
>>
>>
>>
>>    my ($DID, $AMOUNT, $NAME,);
>>     $sth->bind_columns(\($DID, $AMOUNT, $NAME));
>>
>> my $lastN;
>> my $lastA;
>> my @CAMS;
>> my $keepN;
>> my $keepA;
>>
>> while ($sth->fetch) {
>>
>> if ($lastN) {
>>
>>     if ($NAME eq $lastN) {
>>
>>     #print "Combine $AMOUNT, $NAME\n";
>>     $keepA = $AMOUNT + $lastA;
>>     $keepN = $NAME;
>>
>>     } else {
>>
>>     $keepA = $AMOUNT;
>>     $keepN = $NAME;
>>
>>     }
>>
>> }
>>
>> # print "$DID, $AMOUNT, $NAME\n";
>>
>> $lastN = $NAME;
>> $lastA = $AMOUNT;
>>
>> push(@CAMS, $keepA . " " . $keepN);
>>
>>
>> }
>>
>>
>> On Mon, 23 Nov 2015 11:28:40 -0600, Steven Lembark <lembark at wrkhors.com>
>> wrote:
>>
>> On Mon, 23 Nov 2015 10:10:41 -0600
>> richard at rushlogistics.com wrote:
>>
>> > I have a hash reference with the following structure:
>> >
>> > {
>> > '11' => {'AMOUNT' => '20.00','ID' => '11','NAME' => 'Lincoln Park'},
>> > '12' => {'AMOUNT' => '38.00','ID' => '12','NAME' => 'Bucktown'},
>> > '13' => {'AMOUNT' => '41.00','ID' => '12','NAME' => 'Lincoln Park'}
>> > }
>> >
>> > Can anyone tell me how I can combine them by 'NAME' so that I would
>> have:
>> >
>> > {
>> > '11' => {'AMOUNT' => '61.00','ID' => '11','NAME' => 'Lincoln Park'},
>> > '12' => {'AMOUNT' => '38.00','ID' => '12','NAME' => 'Bucktown'},
>> > }
>>
>> You don't seem to care about the keys (loosing key "13" wasn't
>> a problem).
>>
>> Q: Are the ID values important or could they be discarded?
>>
>> If so then just make a new hash keyed by NAME and accumulate
>> the AMOUNT values:
>>
>> my %resultz = ();
>>
>> for( values %inputz )
>> {
>> my ( $name, $amt, $id ) = @{ $_ }{ qw( NAME AMOUNT ID ) };
>> my $val
>> = $resultz{ $name } ||= { ID => $id, NAME => $name };
>>
>> $val->{ AMOUNT } += $amt;
>> }
>>
>> # at this point %resultz is keyed by name with an id and amount
>> # for each entry.
>>
>> %inputz = ();
>>
>> while( my ( $name, $val ) = each %resultz )
>> {
>> $inputz{ $val->{ ID } } = $val;
>> }
>>
>> # at this point the original inputs hash is keyed by ID
>> # with values having a name, accumulated amount, and id.
>> # multiple id's are collapsed into a single ID with the
>> # value of the first record for that name.
>>
>> --
>> Steven Lembark 3646 Flora Pl
>> Workhorse Computing St Louis, MO 63110
>> lembark at wrkhors.com +1 888 359 3508
>> _______________________________________________
>> Chicago-talk mailing list
>> Chicago-talk at pm.org
>> http://mail.pm.org/mailman/listinfo/chicago-talk
>>
>>
>>
>>
>> _______________________________________________
>> Chicago-talk mailing list
>> Chicago-talk at pm.org
>> http://mail.pm.org/mailman/listinfo/chicago-talk
>>
>
>
> _______________________________________________
> Chicago-talk mailing list
> Chicago-talk at pm.org
> http://mail.pm.org/mailman/listinfo/chicago-talk
>



-- 
Sincerely,


Joel Limardo
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.pm.org/pipermail/chicago-talk/attachments/20151123/173202dc/attachment.html>


More information about the Chicago-talk mailing list