use strict; use warnings; my %employees = ( '1' => { boss_id => '1', emp_name => 'big boss', }, '2' => { boss_id => '1', emp_name => 'middle boss', }, '3' => { boss_id => '2', emp_name => 'worker 1', }, '4' => { boss_id => '1', emp_name => 'small boss', }, '5' => { boss_id => '2', emp_name => 'worker 2', }, '6' => { boss_id => '4', emp_name => 'worker 3', }, ); getreports(1); sub getreports { my ($id, $level) = @_; $level = $level || 0; die "Employee $id doesn't exist" if ! exists $employees{$id}; print ' ' x ($level * 3), "|\n", ' ' x ($level * 3), "+- $employees{$id}{emp_name}\n"; my @employees = (); foreach my $emp_id (keys %employees) { # find the employees under $id except # when boss is himself push @employees, $emp_id if $employees{$emp_id}{boss_id} eq $id && $emp_id ne $id; } return if $#employees < 0; getreports($_, $level + 1) foreach (@employees); } #### | +- big boss | +- small boss | +- worker 3 | +- middle boss | +- worker 1 | +- worker 2