Your problem is that _findparent
doesn't return
a usable value if the ID isn't found in the 1st level. Let's take a look at the else
branch:
sub _findparent {
my ($tree, $pid) = @_;
if (my ($parent) = grep { $_->{'id'} == $pid } @$tree) {
...
} else {
for my $i (@$tree) {
say "traversing $i->{'name'} $i->{'id'}";
_findparent($i->{'children'}, $pid) if (ref $i->{'children'} eq 'ARRAY');|
}
}
}
If you don't use an explicit return
, the value of the last statement is returned – here a loop. A loop does not have a useful return value, so you shouldn't use it.
Instead, pass on a useful return value from a lower level:
sub _findparent {
my ($tree, $pid) = @_;
if (my ($parent) = grep { $_->{'id'} == $pid } @$tree) {
...
} else {
for my $i (@$tree) {
say "traversing $i->{'name'} $i->{'id'}";
next if not ref $i->{children} eq 'ARRAY';
my $parent = _findparent($i->{'children'}, $pid);
return $parent if defined $result;
}
return; # return undef if nothing was found
}
}
...
# put the return value in a variable
my $parent = _findparent(...);
# check if the operation was successful
if (not defined $parent) {
die "Tried to find the parent for $id, but there was no matching parent";
}
# if so use the value
push @$parent, ...;
The check can be abbreviated to:
my $parent = _findparent(...) // die "...";
which uses the //
defined-or operator.