#!/usr/bin/perl use strict; use Data::Dumper; my $rows = [ {'Category' => 'Animal', 'Type' => 'Dog', 'Model' => 'Labrador', 'Quantity' => 5}, {'Category' => 'Animal', 'Type' => 'Dog', 'Model' => 'Rottweiler', 'Quantity' => 2}, {'Category' => 'Animal', 'Type' => 'Cat', 'Model' => 'Chartreux', 'Quantity' => 4}, {'Category' => 'Vehicle', 'Type' => 'Car', 'Model' => 'Ford', 'Quantity' => 10}, ]; my $groupedRows = rowsGroupBy($rows, ['Category', 'Type'], { 'SUM' => ['Quantity'] }); print $groupedRows->{'Animal', 'Dog'}->{'Quantity'}; # 7 print "\n"; print Dumper $groupedRows; # $VAR1 = { # 'AnimalCat' => { # 'Type' => 'Cat', # 'Quantity' => 4, # 'Category' => 'Animal' # }, # 'VehicleCar' => { # 'Type' => 'Car', # 'Quantity' => 10, # 'Category' => 'Vehicle' # }, # 'AnimalDog' => { # 'Type' => 'Dog', # 'Quantity' => 7, # 'Category' => 'Animal' # } # }; # $rows: Array of hash_ref (rows) # $groupBy: Array of field to use for the group by. Can be empty if you want to do $options on all rows. # $options: Hash with following option handled: # SUM => @array: Compute the sum. # PILE => @array: Create an array containing all values for the field. # MAX => @array: The greatest value encountered. # Return hash_ref with group by as keys (list) if group by is not empty. # Return hash_ref with $options as keys if group by is empty. sub rowsGroupBy { my($rows, $groupBy, $options) = @_; return undef if @$rows+0 == 0 || !defined($groupBy); my $result = {}; foreach my $row (@$rows) { my $value; my $key = join(chr(28), map { $row->{$_} } @$groupBy); if(exists($result->{$key})) { $value = $result->{$key}; } else { $value = {}; $result->{$key} = $value; } foreach(@$groupBy) { $value->{$_} = $row->{$_}; } foreach(@{$options->{'SUM'}}) { $value->{$_} += $row->{$_}; } foreach(@{$options->{'PILE'}}) { push(@{$value->{$_}}, $row->{$_}); } foreach(@{$options->{'MAX'}}) { $value->{$_} = $row->{$_} if !defined($value->{$_}) || $row->{$_} gt $value->{$_}; } if($options->{'KEEP_UNDERLYING_ROWS'}) { push(@{$value->{'UNDERLYING_ROWS'}}, $row); } } return $result->{''} if @$groupBy == 0; return $result; }