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

I get various arrays that need to be converted to multi-level hash with a value of 1.
For example, if I had:
@array = qw/one two three/;
I will need to return $hash{one}{two}{three} with a value of 1
Any sugestions?
  • Comment on How do I populate a ML hash from an array?

Replies are listed 'Best First'.
Re: How do I populate a ML hash from an array?
by chipmunk (Parson) on Mar 01, 2001 at 02:10 UTC
    You can find some previous discussion of this question in A hash slice but not...

    Here's an updated form of my code example from that discussion:

    use strict; sub nested_value { my $href = shift; my $keys = shift; my $last_key = pop @$keys; for my $key (@$keys) { $href = $href->{$key} ||= {}; } if (@_) { $href->{$last_key} = shift; } return $href->{$last_key}; } my %hash; nested_value(\%hash, [qw/one two three/], 1); print nested_value(\%hash, [qw/one two three/]), "\n"; use Data::Dumper; print Dumper \%hash;
    This subroutine can be used to set and get the value. If there's a third argument to the subroutine, it's set as the new value for the keys; either way the value for the keys is returned.

    Note that this code assumes that each key will either point to a hash reference or to a value. If you set a value first, and then try to use it as a nested hash, you'll get an error from use strict. If you set a nested hash first, and then set a value at the same level, you'll delete the entire nested hash. Error checking could be added to the sub to handle those situations gracefully.

Re: How do I populate a ML hash from an array?
by tye (Sage) on Mar 01, 2001 at 02:00 UTC
Re: How do I populate a ML hash from an array?
by unixdown (Scribe) on Mar 01, 2001 at 03:21 UTC
    Sure enough: I have values set then it tries to place the nested hash in the same level.
    Here is some logs of the last set of arrays sent to the sub:
    02-28-2001 15:18:46 |69 15
    02-28-2001 15:18:46 |69 16
    02-28-2001 15:18:46 |69 18
    02-28-2001 15:18:46 |69 15 14
    02-28-2001 15:18:46 |69 18 17
    02-28-2001 15:18:46 |69 18 19
    02-28-2001 15:18:46 |69 15 14 13
    02-28-2001 15:18:46 |69 15 14 13 12
    02-28-2001 15:18:46 |69 15 14 13 12 11
    02-28-2001 15:18:46 |69 15 14 13 12 11 10
    $hash{69}{15}
    $hash{69}{18}
    Are set first, so all the others are ignored. When really, the least important are the first ({69}{15} & {69}{18}) with the last in the set being critical:
    $hash{69}{15}{14}{13}{12}{11}{10}
    $hash{69}{18}{17}
    $hash{69}{18}{19}
    $hash{69}{16}
    What the script is doing is going through some DB entries and trying to draw a tree from the info it finds. $hash{69}{15}{14}{13}{12}{11}{10} represents a whole leg. My ultimate goal is to draw out the pyramid. I figure that if I could load all the values into the hash, I could just do a recursive iteration of the hash to print out the tree. But since $hash{69}{15} = 1 is set first, the rest of the program errors.
      Why not use an empty hash (ie {}) as your default true value? Then when $hash{69}{15} is set to {}, there is no problem setting $hash{69}{15}{14}{13} to {} after that.
        Well hot-dog!
        Thank you. I was thinking way to hard about that one for such a simple answer.

      Why don't you just use $hash{join $;, @list}= 1 instead?

              - tye (but my friends call me "Tye")
        Because that would produce:
        $hash{onetwothree} = 1
        instead of
        $hash{one}{two}{three} = 1