Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I'd like to know how to transform an array into a datastructure, like:
my @pathparts = split(/\//, "/dir1/dir2/dir3/file1"); my %hash;
@pathparts should be transformed into
$hash{"dir1"}{"dir2"}{"dir3"}{"file1"}
thank you,
frank

Replies are listed 'Best First'.
Re: transform array into a data structure
by jdporter (Paladin) on Sep 28, 2007 at 21:07 UTC
Re: transform array into a data structure
by TGI (Parson) on Sep 28, 2007 at 21:42 UTC

    Don't forget the Data Structures Cookbook, just one part of our lovely perldoc.

    There's so much in the perldoc, it can be overwhelming. You might want to check out perltoc, and the old, yet still relevant How to RTFM.


    TGI says moo

Re: transform array into a data structure (Data::Diver)
by bobf (Monsignor) on Sep 29, 2007 at 03:00 UTC

    Data::Diver solves this problem nicely:

    use strict; use warnings; use Data::Diver qw( DiveVal ); use Data::Dumper; my @pathparts = split(/\//, "dir1/dir2/dir3/file1"); my $href = {}; DiveVal( $href, @pathparts ) = 'value'; print Dumper( $href );
    Note that I removed the leading slash on the path (for convenience). If you don't want empty strings as keys, you could strip them out using grep. This is left as an exercise for the reader.

    Output:

    $VAR1 = { 'dir1' => { 'dir2' => { 'dir3' => { 'file1' => 'value' } } } };

Re: transform array into a data structure
by kyle (Abbot) on Sep 28, 2007 at 21:02 UTC

    Quick and dirty (not recommended):

    # this breaks if @pathparts has a double quote in it! my $element = '$hash' . join '', map { qq|{"$_"}| } @pathparts; eval "$element = undef";

    Slightly more respectable:

    my $step = \%hash; while ( my $part = shift $pathparts ) { $step->{$part} ||= {}; $step = $step->{$part}; }

    We might be able to help you better if you tell us what you're really trying to do (see XY Problem).

Re: transform array into a data structure
by perlfan (Parson) on Sep 29, 2007 at 00:30 UTC
    Here is a recursive solution written more for clarity than conciseness. It'll give a basic idea anyway:
    #!/user/bin/env perl use strict; use warnings; use Data::Dumper; my @array = qw(a b c d e f g h i 123); my $recurse_level = 0; sub to_hash { my $hash_ref = shift; my @array = @_; my $array_count = @array; die "Need at least 2 elements in original array" if (0 == $recurse_l +evel && 2 > $array_count); my $index; if (2 < $array_count) { $index = shift @array; $recurse_level++; $hash_ref->{$index} = to_hash({},@array); } else { $index = shift @array; $hash_ref->{$index} = shift @array; } return $hash_ref; } my $hash_ref = to_hash({},@array); print Dumper($hash_ref);
    Output:
    $VAR1 = { 'a' => { 'b' => { 'c' => { 'd' => { 'e' => { 'f' => { 'g' => + { + 'h' => { + 'i' => '123' + } + } } } } } } } };
    Update

    Triple bonus points to whomever modifies this code to allow for more complex data structures to be created by feeding it multiple arrays - the current code only returns a hash for /the/ array passed to it. I know why, but I can figure out right now how to fix it...if I figure it out, I'll update the code.

      Do I get a simple bonus if I turn your code into a one liner :)

      my $h = pop @array; $h = {$_ => $h} for reverse @array;
Re: transform array into a data structure
by graff (Chancellor) on Sep 30, 2007 at 00:14 UTC
    Heh, seems like lots of people have written solutions for this sort of problem. Here's the one I wrote: Re: seeking in hash data structure (can handle a list of strings being parsed into a single hash structure, and includes a "trace" sub to look for a given hash key anywhere in the structure).

    It's the same sort of process that's used in building "Trie" trees over a list of words (to analyze "prefix patterns" by building this sort of hash from the letters that spell the words), and there are a few different CPAN solutions for that.