use 5.016; # For __SUB__, or pre-declare $grep and use $grep->() syntax sub ref_grep(&$) { my ($wanted, $ref) = @_; my $seen = {}; # Refs we've already seen (avoid circular refs) my @found; # Result list my $grep = sub { my ($ref, $path) = @_; return if ref $ref and $seen->{$ref}++; { $_ = $ref; push @found, $path if $wanted->() } for (ref $ref) { when ('HASH') { __SUB__->($ref->{$_}, $path."->{$_}") for sort keys $ref; } when ('ARRAY') { __SUB__->($ref->[$_], $path."->[$_]") for sort keys $ref; } } }; $grep->($ref, ''); return @found; }