Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

Is it possible to use key/values of a Hash/Hash ref while it's being initialized?

by shiza (Hermit)
on Sep 14, 2005 at 19:55 UTC ( [id://491993]=perlquestion: print w/replies, xml ) Need Help??

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

Say we have:
my %hash = ( key1 => 'longstring', key2 => alter('longstring'), );

Basically, I'd like to do something like:
my %hash = ( key1 => 'longstring', key2 => alter($hash{key1}), );

This is just out of curiosity. I'm well aware of other ways to accomplish the same. For instance:
my $s = 'longstring'; my %hash = ( key1 => $s, key2 => alter($s), );


UPDATE:
-----------------------------------------
I appreciate the solutions provided thus far, but in order to help everyone see what I'm trying to do, I'll add some more detail:
my %hash = map {$_ => { key1 => 'longstring'.$_.'more', key2 => alter('longstring'.$_.'more') } } @list;

The value of key1 has to be laying around somewhere?!?
------------------------------------------
Thanks in advance.

Replies are listed 'Best First'.
Re: Is it possible to use key/values of a Hash/Hash ref while it's being initialized?
by ikegami (Patriarch) on Sep 14, 2005 at 20:04 UTC

    Yes:

    my %hash; $hash{key1} = 'longstring'; $hash{key2} = alter($hash{key1});

    Admittedly, you have to change your initialization syntax somewhat. The reason is that list on the right hand side of the = is built before the assignment even starts. (See perlop for operator precedence.) Some people seem to think %h = (a=>b, c=>d); is a hash constructor/initializer, but it's not. It's simply a list which gets assigned to a hash.

      /me goes to delve into perlop. Thanks!
Re: Is it possible to use key/values of a Hash/Hash ref while it's being initialized?
by fishbot_v2 (Chaplain) on Sep 14, 2005 at 21:23 UTC
    The value of key1 has to be laying around somewhere?!?

    No, but you can bookmark it if you want:

    my %hash = map { my $foo; $_ => { key1 => $foo = 'longstring'.$_.'more', key2 => alter( $foo ), } } @list;

    That would work, though I am not sure I would recommend it. A two-stage approach would/might be cleaner, I think:

    my %hash = map { my $foo = { key1 => 'longstring'.$_.'more' }; $foo->{"key2"} = alter( $foo->{"key1"} ); $_ => $foo; } @list;

    Actually, now that I've written both, I can't decide which is cleaner.

      or

      my %hash = map { my $foo = 'longstring'.$_.'more'; $_ => { key1 => $foo, key2 => alter($foo) } } @list;

      or (the wacky)

      my %hash = map { $_->[0] => { key1 => $_->[1], key2 => alter($_->[1]) } } map { [ $_ => 'longstring'.$_.'more' ] } @list;

      or (the efficient)

      my %hash; foreach (@list) { my $foo = 'longstring'.$_.'more'; $hash{$_} = { key1 => $foo, key2 => alter($foo), }; }

      or (using auto-vivification)

      my %hash; foreach (@list) { my $foo = 'longstring'.$_.'more'; $hash{$_}{key1} = $foo; $hash{$_}{key2} = alter($foo); }

      or

      my %hash; foreach my $key (@list) { foreach ('longstring'.$key.'more') { $hash{$key} = { key1 => $_, key2 => alter($_), }; } }

      or

      my %hash; foreach my $key (@list) { foreach ('longstring'.$key.'more') { $hash{$key}{key1} = $_; $hash{$key}{key2} = alter($_); } }

      or (in two steps)

      my %hash = map { $_ => { key1 => 'longstring'.$_.'more' } } @list; $hash{$_}{key2} = alter($hash{$_}{key1}) foreach keys %hash;

      Updated: Added more alternatives.

      Updated: Fixed bug. Changed $_ to $key in the concatenation in later snippets.

      Updated: Added more alternatives.

Re: Is it possible to use key/values of a Hash/Hash ref while it's being initialized?
by davidrw (Prior) on Sep 14, 2005 at 20:01 UTC
    no -- run it and then Dumper %hash -- you'll see that the second key is empty (or blank, depeding on what alter does). If you run with strict/warnings it will error with 'Global symbol "%hash" requires explicit package name' ...

    another alternative would be: </code> my %hash = ( key1 => 'longstring' ); $hash{key2} = alter( $hash{key1} ); </code>
      Yes, I was aware of that. I didn't know if there was some backdoor/hack/trick to access the current hash being initialized. Thanks for the feedback!
        the current hash being initialized
        That hash is necessarily empty until the entire value on the right (the map) is completely computed. You can't start shoving values into there because you can't alter the existing data, or else things like this woudn't work:
        @a = map { $a[$_] > 1 ? $a[$_] * 2 : () } 0..$#a;
        In this case, you can't start altering @a during the map, because @a might be getting shorter, and then you wouldn't have the right values on the right.

        -- Randal L. Schwartz, Perl hacker
        Be sure to read my standard disclaimer if this is a reply.

Re: Is it possible to use key/values of a Hash/Hash ref while it's being initialized?
by goldclaw (Scribe) on Sep 15, 2005 at 08:45 UTC
    One way is to put in a subroutine to create the inner hash for you. If you prefer to have everything located inside the map, thats easy using an anonymous sub:
    my %hash = map {$_ => { sub { key1 => $_[0], key2 => alter($_[0]) }->('longstring'.$_.'more') } } @list;
    To answer your original question, in short: no. Before its initialized there is nothing there to use.

    Basically you assign a list to the hash, and that list has to be constructed before it can be assigned, and its while you are constructing this list that you want to use one of its earlier elements to create a later one. Using a sub, you can create the element in question first(when providing the arguments to the sub call), and then create the list.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://491993]
Approved by gargle
Front-paged by gargle
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (5)
As of 2024-03-28 23:46 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found