Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Creating pointers in a HoH declaration

by cmv (Chaplain)
on Apr 29, 2016 at 18:38 UTC ( [id://1161900]=perlquestion: print w/replies, xml ) Need Help??

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

Hi Monks-

I'm a little embarrassed to ask this question, as I feel I should know the answer - however, I haven't been able to come up with a good answer (by searching or thinking) for 2 days! Please help - my mind is going...

I want to declare a hash-of-hashes, where some of the elements point to each other. Is it possible to do it in a declaration? Here is some code that makes it happen outside the declaration.

Any help is much appreciated!

Thanks

-Craig

use strict; use warnings; use Data::Dumper; my %fields = ( version1 => { 1 => 'Field 1', 2 => 'Field 2', 3 => 'Field 3', }, version2 => { 1 => 'Field 1', 2 => 'Field 2', 3 => 'Field 3', 4 => 'Field 4', }, version3 => { 1 => 'Field 1', 2 => 'Field 2', 3 => 'Field 3', 4 => 'Field 4', 5 => 'Field 5', }, version4 => { # What if version4 is exactly the same as version3. # How do I just make version4 point to verson3? }, ); print STDERR "fields Dump1:\n", Dumper(\%fields), "\n"; $fields{version4} = $fields{version3}; print STDERR "fields Dump2:\n", Dumper(\%fields), "\n";

Replies are listed 'Best First'.
Re: Creating pointers in a HoH declaration
by AnomalousMonk (Archbishop) on Apr 29, 2016 at 18:56 UTC

    This is tricky because the  %fields hash (or any other object) isn't accessible until the statement is successfully executed; i.e., until the  ; (semicolon) at the end of the
        my %fields = ( ... );
    is encountered.

    You either have to have all the low-level anonymous hash references prepared before you begin defining the  %fields hash, or add them afterward.

    It's even more tricky because the other thing to seriously consider is if you really want a copy of the hash reference to a hash with identical content, or a deep copy of the content of that identical hash.

    Updates:

    1. Added Wikipedia link for "deep copy", some minor wording changes.
    2. As an example of what happens when you just make copies of references, consider:
      c:\@Work\Perl\monks>perl -wMstrict -MData::Dumper -le "my $hr_same_content = { 1 => 'Ok' }; ;; my %fields = ( version1 => $hr_same_content, version_TWO => $hr_same_content, ); print Dumper \%fields; ;; $fields{version1}{1} = 'Oops...'; ;; print $fields{version_TWO}{1}; " $VAR1 = { 'version_TWO' => { '1' => 'Ok' }, 'version1' => $VAR1->{'version_TWO'} }; Oops...
      (The  'version1' => $VAR1->{'version_TWO'} entry in the Dumper listing means that the reference that is the value of the  'version1' key is equal to the reference that is the value of the  'version_TWO' key of the hash.)
      So again, do you want to copy content or references to content?
    3. If you haven't already, you might want to take a look at the Perl Data Structures Cookbook (or  perldoc perldsc from your friendly, local command line).
    4. Even pre-defining  %fields doesn't help:
      c:\@Work\Perl\monks>perl -wMstrict -MData::Dumper -le "my %fields; %fields = ( version1 => { 1 => 'Ok' }, version_TWO => $fields{version1}, ); print Dumper \%fields; ;; $fields{version1}{1} = 'Oops...'; ;; print $fields{version_TWO}{1}; " $VAR1 = { 'version_TWO' => undef, 'version1' => { '1' => 'Ok' } }; Use of uninitialized value in print at -e line 1.
      This works:
      c:\@Work\Perl\monks>perl -wMstrict -MData::Dumper -le "my %fields = ( version1 => { 1 => 'Ok' }, ); $fields{version_TWO} = $fields{version1}; print Dumper \%fields; print $fields{version1} {1}; print $fields{version_TWO}{1}; ;; $fields{version1}{1} = 'Oops...'; ;; print $fields{version1} {1}; print $fields{version_TWO}{1}; " $VAR1 = { 'version_TWO' => { '1' => 'Ok' }, 'version1' => $VAR1->{'version_TWO'} }; Ok Ok Oops... Oops...
      but, of course, still the problem of copying references.


    Give a man a fish:  <%-{-{-{-<

Re: Creating pointers in a HoH declaration
by NetWallah (Canon) on Apr 29, 2016 at 20:43 UTC
    Here is a somewhat clunky delayed evaluation trick:
    my %f; %f=(One=>1, two=>sub{$f{One}} ); # Flatten all the subs .. ref $f{$_} eq 'CODE' and $f{$_}=$f{$_}->() for keys %f; print Dumper \%f; # All populated
    Output:
    $VAR1 = { 'two' => 1, 'One' => 1 };
    Update: Verified that this works fine (i.e. 'One' and 'two' point to the same data) for HOH - i.e for:
    my %f; %f=(One=>{this=>'that'}, two=>sub{$f{One}});

            This is not an optical illusion, it just looks like one.

Re: Creating pointers in a HoH declaration
by graff (Chancellor) on Apr 30, 2016 at 16:11 UTC
    I'm afraid I don't see any compelling reason to do this sort of thing in a single initialization step. You're just doing an initialization; you already know, in advance of writing the code, that you need multiple hash keys that point to the same data, and I gather you've already established that the "normal" way of doing this does what you intend, so it would seem clearer, cleaner, and more maintainable to be explicit about how the initialization is done:
    my %fields = ( version1 => { 1 => 'Field 1', 2 => 'Field 2', 3 => 'Field 3', }, version2 => { 1 => 'Field 1', 2 => 'Field 2', 3 => 'Field 3', 4 => 'Field 4', }, version3 => { 1 => 'Field 1', 2 => 'Field 2', 3 => 'Field 3', 4 => 'Field 4', 5 => 'Field 5', }, ); my %synonyms = ( version4 => 'version3', # ... maybe you want others? ... ); $fields{$_} = $fields{ $synonyms{$_} } for ( keys %synonyms );

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others rifling through the Monastery: (6)
As of 2024-04-25 18:06 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found