use Scalar::Util 'reftype'; my %path = ( ARRAY => \&_array_path, HASH => \&_hash_path, ); sub path { my ( $data, $search ) = @_; my $type = reftype $data; my $find_paths = $path{$type}; return $find_paths->( $data, $search ); } sub _array_path { my ( $data, $search ) = @_; my @paths; foreach my $i (0 .. $#$data) { my $item = $data->[$i]; my $type = reftype $item; my $current_index = "[$i]"; if ( !$type && $item eq $search ) { # XXX push @paths => $current_index; } elsif ( my $find_paths = $path{$type} ) { my @current_paths = map { "$current_index$_" } @{ $find_paths->( $item, $search ) }; push @paths => @current_paths; } } return \@paths; } sub _hash_path { my ( $data, $search ) = @_; my @paths; foreach my $key (keys %$data) { my $item = $data->{$key}; my $type = reftype $item; my $current_key = "{$key}"; if ( !$type && $item eq $search ) { # XXX push @paths => $current_key; } elsif ( my $find_paths = $path{$type} ) { my @current_paths = map { "$current_key$_" } @{ $find_paths->( $item, $search ) }; push @paths => @current_paths; } } return \@paths; }