my $in = [ {c_id => 1, r_to => 0, dept => 0, p_id => 1, comm => 'this',}, {c_id => 3, r_to => 1, dept => 1, p_id => 1, comm => 'the other',}, {c_id => 5, r_to => 1, dept => 1, p_id => 1, comm => 'else',}, {c_id => 6, r_to => 5, dept => 2, p_id => 1, comm => 'that',}, {c_id => 7, r_to => 6, dept => 3, p_id => 1, comm => 'moreover',}, {c_id => 9, r_to => 3, dept => 2, p_id => 1, comm => 'no way',}, {c_id => 10, r_to => 9, dept => 3, p_id => 1, comm => 'give',}, ]; #### 1: this - 3: the other - 9: no way - 10: give - 5: else - 6: that - 7: moreover #### traverse($in,0,0, sub {print ' ' x $_->{dept},'-',$_->{comm},"\n";}); sub traverse { my( $ref, $reply_to, $depth, $code) = @_; for my $node ( grep{ ($_->{dept} == $depth) && ($_->{r_to} == $reply_to) } @$ref ) { local $_ = $node; $code->(); traverse($ref, $node->{c_id}, ($depth + 1), $code); } } #### traverse($in, 0, 0); sub traverse { my( $ref, $reply_to, $depth) = @_; for ( grep{ ($_->{dept} == $depth) && ($_->{r_to} == $reply_to) } @$ref ) { print ' ' x $_->{dept}, '-', $_->{comm}, "\n"; traverse($ref, $_->{c_id}, ($depth + 1)); } }