use strict; use warnings; use Data::Dumper qw/Dumper/; my $input = get_input(); my $second = $input->{1929}; my ( $tree, @roots ); while ( my ( $id, $attr ) = each %$second ) { my $boss_id = $attr->{boss}; my $name = $attr->{name}; unless ( $boss_id ) { push @roots, $name; next } my $boss_name = $second->{$boss_id}->{name}; $tree->{$boss_name}{$name} = $tree->{$name} //= {}; } #$Data::Dumper::Indent = 1; $Data::Dumper::Terse = 1; #$Data::Dumper::Pad = '#'; $Data::Dumper::Quotekeys = 0; #$Data::Dumper::Pair = ' : '; print Dumper { map { $_ => $tree->{$_} } @roots }; sub get_input{ return { 1929 => { 1 => { boss => 1929, name => "Hermes" }, 2 => { boss => 1, name => "Leela" }, 3 => { boss => 1929, name => "Amy" }, 4 => { boss => 1, name => "Zoidberg" }, 480 => { boss => 2, name => "Fry" }, 1919 => { boss => 2, name => "Bender" }, 1929 => { boss => 0, name => "Professor" }, 3968 => { boss => 1929, name => "Cubert" }, 4425 => { boss => 1, name => "Dwight" }, }, }; }