If your hash structure is always HoHoHo... -- i.e. no arrays, just hashes -- then the first trick you need to nail down is a way to distinguish between terminal nodes and non-terminal nodes in your tree.
Based on your examples, I'd guess that the easiest way to do this is by using your actual strings only as hash keys, never as values assigned to keys. The value of a hash element would always be a hash ref; non-terminal nodes would contain hash refs with one or more keys, whereas a terminal node would contain an empty hashref. The point here is that hash value is either a simple scalar or else it's a reference -- it can't be both.
Here's a way you could take hyphen-delimited strings to create an abitrarily deep / arbitrarily wide tree structure:
use strict;
use warnings;
use Data::Dumper;
sub load_hash
{
my ( $href, $path ) = @_;
my @path = split /-/, $path;
my $key = shift @path;
while ( @path and exists( $$href{$key} )) {
$href = $$href{$key};
$key = shift @path;
}
if ( ! exists( $$href{$key} )) { # there's a new key in this path
$$href{$key} = {}; # so create a new hashref for it
load_hash( $$href{$key}, join( "-", @path )) if ( @path );
# recurse if this key/node is non-terminal
}
# otherwise, do nothing -- the path already exists in the structure
}
sub trace_paths # look for paths to a chosen node (hash key)
{
my ( $href, $aref, $node, $path ) = @_;
$path ||= '';
my @keys = keys %$href;
if ( grep /^$node$/, @keys ) {
push @$aref, ( $path ) ? "$path-$node" : $node;
}
for my $key ( @keys ) {
my $nxt_path = ( $path ) ? "$path-$key" : $key;
trace_paths( $$href{$key}, $aref, $node, $nxt_path )
if ( scalar keys %{$$href{$key}} );
}
}
my @strings = qw/one-foo-bar-baz one-foo-zuz
two-fump-zill two-fizz-foo/;
my %hash;
load_hash( \%hash, $_ ) for ( @strings );
print Dumper( \%hash );
my @found;
trace_paths( \%hash, \@found, 'foo' );
print Dumper( \@found );
(updated to fix an annoying initial dash in @found values)
Now, if you really want the structure to hold scalar values as well as hash keys, you'll need to reserve one or more "special keys" that you can use for storing strings or numbers instead of lower-level hash refs. These special keys need to be strings that will never occur as data (nodes in the structure), and the load_hash and/or trace_paths subs would need an extra line or two of code to use them as needed.
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.