use strict; use warnings; use Data::Dump qw/pp dd/; # --- input data my @sorted_data = ( { 'count_payment' => '', 'count_banking' => '31 (62.00)', 'name' => 'Parking Eye [LTD] One', }, { 'count_payment' => '10 (144.00)', 'count_banking' => '', 'name' => 'Parking Eye [LTD] Two', }, { 'count_payment' => '2 (80.42)', 'count_banking' => '', 'name' => 'Parking Eye [LTD] Three', }, { 'count_payment' => '', 'count_banking' => '4 (982.00)', 'name' => 'Parking Eye [LTD] Two', } ); # --- join elements into temporary hash by name my %tmp_hash; my $order = 0; for my $record (@sorted_data) { my $name = $record->{name}; # create new hash only if $name unknown $tmp_hash{$name} //= { name => $name, _order => $order++, # preserve original order }; # concat other elements for (qw/count_banking count_payment/) { $tmp_hash{$name}{$_} .= $record->{$_}; } } # --- copy hash values by order my @new_sorted_data = sort { $a->{_order} <=> $b->{_order} } values %tmp_hash; # --- discard temporary _order element delete $_->{_order} for @new_sorted_data; # --- dump result pp \@new_sorted_data;