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

Hi Monks, I have for example,
@a = ( 1, 2 ,3 , "a");
I want to create $Hash{1}{2}{3}{"a"} = 1; . I am having diffculty trying to create a function to do this. Any help? I have to do this on a large scale (so manual labour isn't a good option). Note : I have no idea beforehand how many elements are in the array , meaning it's dynamic

Replies are listed 'Best First'.
Re: Hash key manipulation question
by davido (Cardinal) on Jan 11, 2005 at 19:18 UTC

    Sometimes it's easier to do it all backwards:

    use strict; use warnings; use Data::Dumper; my @a = ( 1, 2, 3, "a" ); my %Hash = do { my $hashref = 1; $hashref = { $_ => $hashref } for reverse @a; %{$hashref}; }; print Dumper \%Hash;

    This algorithm is very similar to one used to create linked lists, demonstrated in Mastering Algorithms with Perl, published by O'Reilly & Associates.

    The way this works is by assigning your final value to $hashref. Then you work backwards through @a, setting $hashref equal to $hashref->{a}=1, and then to $hashref->{3}{a}=1, and then to $hashref->{2}{3}{a}=1, and so on, each time adding one more higher layer. In the end, you asked for %Hash, not $hashref, so this snippet dereferences $hashref for you and hands you %Hash. The do{...} block is used to limit the scope of $hashref, and to compartmentalize the entire operation in one nice little package.

    Enjoy!


    Dave

Re: Hash key manipulation question
by BrowserUk (Patriarch) on Jan 11, 2005 at 18:58 UTC

    See hash problem.


    Examine what is said, not who speaks.
    Silence betokens consent.
    Love the truth but pardon error.
Re: Hash key manipulation question
by Tanktalus (Canon) on Jan 11, 2005 at 19:01 UTC

    Off the top of my head, a relatively inefficient method:

    eval '$Hash' . map { qq({'$_'}) } @a . ' = 1';

    Untested, of course ;-) A bit of description in order here: we're just creating the string you wanted. A bit more smarts to only put in the quotes when required, check if the hash you're trying to create already exists as a scalar rather than a hashref, etc., to prevent collisions, ... but if you know that collisions can't happen, then this should be fine.

    UPDATE:After reading the other hash thread, I see someone of importance saying "don't use eval". And, as a general rule, I would agree. But I don't know if this is a one-off script (just do a quick conversion, and never use it again), or if the input is tightly controlled (e.g., can't be manipulated to circumvent perl security-isms, e.g., a string that had single-quotes in it: qq(blah' . system("rm -rf /") . 'blah)), or other mitigating circumstances. Sometimes quick and dirty is fine. A more robust method would use loops or even recursion to do this.

    sub create_hash_depth { my $href = shift; my @a = @_; if (scalar @a > 1) { $href->{$a[0]} = {}; create_hash_depth($href->{$a[0]}, @a[1..$#a]); } else { $href->{$a[0]} = 1; } }

    Or something like that

      lol, i just read the other thread too. I have heard eval is dangerous to use. Thanks for all your help guys.
Re: Hash key manipulation question
by holli (Abbot) on Jan 11, 2005 at 19:23 UTC
    use strict; use Data::Dumper; my @a = (1, 2 ,3 , "a"); my %h; a2h (\@a, \%h); print Dumper (\%h); print $h{1}{2}{3}{a}; sub a2h { my $array = shift; my $hash = shift; my $index = 0; while ( $index < $#$array ) { $hash = $hash->{$array->[$index]} = {}; $index++; } $hash->{$array->[$index]} = 1; return $hash; } #Output: # #$VAR1 = { # '1' => { # '2' => { # '3' => { # 'a' => 1 # } # } # } # }; #1