use strict; use warnings; use List::Util 'reduce'; use List::MoreUtils 'mesh'; use Data::Dumper; my %t = ( a => 1, b => 2, c => 1, d => 2, e => 1, f => 2, g => 3 ); my( $k, $v ) = @{ +reduce { if( $a->[0]->[-1] eq $b->[0]->[0] ) { push @{$a->[1]->[-1]}, $b->[1]->[0]->[0]; } else { push @{$a->[0]}, $b->[0]->[0]; push @{$a->[1]}, [$b->[1]->[0]->[0]]; } $a; } map { [ [$t{$_}], [[$_]] ] } sort { $t{$a} <=> $t{$b} } keys %t }; my %i = mesh @$k, @$v; print Dumper \%i;