I've been trying to figure out this one-liner, and can't seem to get it to work.
Say I have this reference to an array of hashrefs:
my $payments = [
{
'receipt_id' => '100',
'payment_id' => '1',
'payment_amount' => 20,
},
{
'receipt_id' => '100',
'payment_id' => '1',
'payment_amount' => 30,
},
{
'receipt_id' => '100',
'payment_id' => '2',
'payment_amount' => 40,
},
{
'receipt_id' => '200',
'payment_id' => '1',
'payment_amount' => 20,
},
];
What I'd like to do is create a hash where the key is the payment_id, and the value is the sum of all payment_amounts for a particular receipt_id.
I can do:
my %sum_payments = map { $_->{payment_id} => $_->{payment_amount} }
grep { $_->{receipt_id} eq '100' }
@$payments;
And get:
1 => 30,
2 => 40,
But when I try:
my %sum_payments = map { $_->{payment_id} => (sum map { $_->{payment_amount} }) }
grep { $_->{receipt_id} eq '100' }
@$payments;
It throws errors.
How can I write a one-liner using map / grep to get:
1 => 50,
2 => 40,
Also, I know there are many other ways to achieve the same thing. I'm interested to know if this is possible using a single statement with map / grep.
You just need something to accumulate into - such as assigning directly into the destination hash:
my %sum_payments;
map { $sum_payments{$_->{payment_id}} += $_->{payment_amount} }
grep { $_->{receipt_id} eq '100' }
@$payments;
This is similar to @toolic's answer but, as that says, less readable (and I think less inefficient on large input due to grep building an intermediate list), and some people don't like map
used like this.