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

I have a hash structure(s) that I would like to store within the array +, for example like a new record within a table. Here is my code:
#!/usr/bin/perl -w use strict; use Data::Dumper; # The objective of the application is to demonstrate # how to use # Build an array of hashes. my @data2 = ( { "DR"=>[0,0,0,0,0], "SAT ITAMS"=>[0,0,0,0,0], "PROD ITAMS"=>[0,0,0,0,0] } ); # End of the array. my @data=({}); my $work_request = { "DR"=>[0,0,0,0,0], "SAT ITAMS"=>[0,0,0,0,0], "PROD ITAMS"=>[0,0,0,0,0] }; for ( my $indx = 0; $indx <=2; $indx++){ # Make a reference to the hash reference my $work_package = \%{$work_request}; # The hash should be constructed dynamically? foreach my $key (keys %{$work_package}){ my @list = @{$work_package->{$key}}; for (my $a_id=0; $a_id <= $#list; $a_id++) { $list[$a_id]=$indx; print " $list[$a_id]\t"; } print "\n"; } print"\n"; # Add the hash reference to the array #push (@data, %{$work_package}) push (@data, \%{$work_package}); } # Printing out the array of hashes list. # Now is print out the array of hashes. for ( my $indx = 0; $indx <=2; $indx++){ # Make a reference to the hash reference my $work_package = pop(@data); # The hash should be constructed dynamically? foreach my $key (keys %{$work_package}){ #print "$key\t"; my @list = @{$work_package->{$key}}; for (my $a_id=0; $a_id <= $#list; $a_id++) { print " $list[$a_id]\t"; } print "\n"; } print"\n"; } The output I get is the following: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
I haven't be able to preserve the values. Can someone help me?

Replies are listed 'Best First'.
Re: Array of dynamic Hash how to preserve the values
by dwm042 (Priest) on Mar 25, 2009 at 17:55 UTC
    Core problem is too much indirection, which means you are making references back to an original when you probably intend to make copies. I won't dig too deep into this, but I'll show code that illustrates the problem.

    This code just makes pointers to a single version of the structure, without making copies of the structure's changes.

    #!/usr/bin/perl use warnings; use strict; use Data::Dumper; my @data=({}); my %work_request = ( "DR"=>[0,0,0,0,0], "SAT ITAMS"=>[0,0,0,0,0], "PROD ITAMS"=>[0,0,0,0,0] ); #push @data, [ %work_request ]; push @data, \%work_request; $work_request{DR} = [1,2,3,4]; #push @data, [ %work_request ]; push @data, \%work_request; print Dumper( @data );
    and the output is:

    C:\Code>perl how_many_indirects.pl $VAR1 = {}; $VAR2 = { 'PROD ITAMS' => [ 0, 0, 0, 0, 0 ], 'SAT ITAMS' => [ 0, 0, 0, 0, 0 ], 'DR' => [ 1, 2, 3, 4 ] }; $VAR3 = $VAR2;


    This version of code copies the unique components as the base structure changes.

    #!/usr/bin/perl use warnings; use strict; use Data::Dumper; my @data=({}); my %work_request = ( "DR"=>[0,0,0,0,0], "SAT ITAMS"=>[0,0,0,0,0], "PROD ITAMS"=>[0,0,0,0,0] ); push @data, [ %work_request ]; #push @data, \%work_request; $work_request{DR} = [1,2,3,4]; push @data, [ %work_request ]; #push @data, \%work_request; print Dumper( @data );
    and the output is:

    C:\Code>perl how_many_indirects.pl $VAR1 = {}; $VAR2 = [ 'PROD ITAMS', [ 0, 0, 0, 0, 0 ], 'SAT ITAMS', [ 0, 0, 0, 0, 0 ], 'DR', [ 0, 0, 0, 0, 0 ] ]; $VAR3 = [ 'PROD ITAMS', $VAR2->[1], 'SAT ITAMS', $VAR2->[3], 'DR', [ 1, 2, 3, 4 ] ]; C:\Code>
Re: Array of dynamic Hash how to preserve the values
by locked_user sundialsvc4 (Abbot) on Mar 25, 2009 at 18:43 UTC

    It's easy to become “lost” when you start trying to build complex data-structures in Perl. Specifically, you can lose sight of what is actually occurring, i.e. “according to Perl,” just because “it seems to work okay.”

    Remember this always:   an array, like its half-brother the hash, always contains one thing per “bucket.” That one thing can be ... a scalar, undef, or a reference to something else.

    So, you can never really have “an array of hashes.” What you've actually got is “an array of hash-refs.”

    When you, unintentionally or otherwise, push through “a reference to something else,” where you wind up is that “something else.” Perl's syntax rules are pretty darned generous, and you can easily wind up thinking that you are telling Perl one thing, but Perl is interpreting it as another thing, and it appears to be “working.” The difference is subtle, and extremely important, but not at all obvious.

Re: Array of dynamic Hash how to preserve the values
by jwkrahn (Abbot) on Mar 25, 2009 at 18:02 UTC
    for ( my $indx = 0; $indx <=2; $indx++){

    That is usually written as:

    for my $indx ( 0 .. 2 ) {

    # Make a reference to the hash reference my $work_package = \%{$work_request};

    You have a hash reference in $work_request which you then dereference as %{$work_request} and then get a reference to the original hash with \%{$work_request}.   You can accomplish the same thing more simply with:

    my $work_package = $work_request;

    my @list = @{$work_package->{$key}}; for (my $a_id=0; $a_id <= $#list; $a_id++) { $list[$a_id]=$indx; print " $list[$a_id]\t"; } print "\n";

    You are copying the contents of @{$work_package->{$key}} to @list so any changes to the contents of @list will disapear when the loop ends.   The for loop is usually written as:

    for my $a_id ( 0 .. $#list ) { $list[$a_id]=$indx; print " $list[$a_id]\t"; }