Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Re^3: Strange hash array behavior

by Util (Priest)
on Jan 29, 2009 at 05:02 UTC ( [id://739763]=note: print w/replies, xml ) Need Help??


in reply to Re^2: Strange hash array behavior
in thread Strange hash array behavior

Can you modify the code above to produce the result I am looking for...?
You are making a shallow copy. You need a deep copy.
Change this:
$r->{sizes} = $data2;
to:
$r->{sizes} = [ map { { %{$_} } } @{$data2} ];
or
use Clone qw( clone ); $r->{sizes} = clone($data2);
or
use Clone::PP qw( clone ); $r->{sizes} = clone($data2);
or
use Storable qw( dclone ); $r->{sizes} = dclone($data2);

Replies are listed 'Best First'.
Re^4: Strange hash array behavior
by Rodster001 (Pilgrim) on Jan 29, 2009 at 05:19 UTC
    Okay, cool that worked. I guess I just don't really conceptually get why the first iteration works but after that I get a shallow copy.

    I think the reason why I am confused is because this works and it seems to be the same concept (to me):

    my $data1 = [ { "shape" => "round", "food" => "apple" }, { "shape" => "square", "food" => "pear" }, { "shape" => "oval", "food" => "grape" }, ]; my $test = $data1; my $test2 = $test; my $test3 = $test2; print Dumper($test3);
    Update: Or an even better example of why I am confused:
    my $data1 = [ { "shape" => "round", "food" => "apple" }, { "shape" => "square", "food" => "pear" }, { "shape" => "oval", "food" => "grape" }, ]; foreach (0..5) { my $copy = $data1; print Dumper($copy); }
    Update: And yet an even better example... why the heck does this work and not the previous examples?
    use Data::Dumper; my $data1 = [ { "shape" => "round", "food" => "apple" }, { "shape" => "square", "food" => "pear" }, { "shape" => "oval", "food" => "grape" }, ]; my $data2 = [ { "big" => "cow", "small" => "bunny" }, { "big" => "horse", "small" => "mouse" }, ]; foreach (0..2) { my $d = $data1->[$_]; $d->{sizes} = $data2; print Dumper($d); }
    Last Update!: Using the same data above, this does not work:
    my @array; foreach (0..2) { my $d = $data1->[$_]; $d->{sizes} = $data2; push(@array,$d); } print Dumper(\@array);
    But this does, so I guess I just don't understand why it (the above) works on the first iteration but not any after. Is that really behaving like it is suppose to?
    my @array; foreach (0..2) { my $d = $data1->[$_]; $d->{sizes} = $data2; push(@array,clone($d)); } print Dumper(\@array);
    Thanks again for the fix!

      my @array; foreach (0..2) { my $d = $data1->[$_]; $d->{sizes} = $data2; push(@array,$d); } print Dumper(\@array);

      The underlying problem is that you think $data2 contains a hash or array (depending on the snippet), but it doesn't. It contains a reference to a hash an an array.

      When you assign $data2 to something, you're copying the reference, that's it. All your questions boil down to "Why doesn't copy the referenced hash or array?", and the answer is always "Because you didn't ask it to."

      I just don't really conceptually get why the first iteration works but after that I get a shallow copy.

      You never get a copy of the array referenced by $data2, not even the first time through the loop. Every time through the loop you set $r->{sizes} to be a reference to the same original anonymous array. If you want a new array you have to create it. util has shown you several ways you can make a copy of the array referenced by $data2. Having created a copy of the original array, you can then set $r->{sizes} to be a reference to the copy.

        You never get a copy of the array referenced by $data2, not even the first time through the loop.
        But, it seems to work on the first iteration. util's fix solved the problem and that is the route I am going to go. This is purely academic at this point. So, my last example above (using the same data)...
        my @array; foreach (0..2) { my $d = $data1->[$_]; $d->{sizes} = $data2; push(@array,$d); } print Dumper(\@array); $VAR1 = [ { 'food' => 'apple', 'shape' => 'round', 'sizes' => [ { 'small' => 'bunny', 'big' => 'cow' }, { 'small' => 'mouse', 'big' => 'horse' } ] }, { 'food' => 'pear', 'shape' => 'square', 'sizes' => $VAR1->[0]{'sizes'} }, { 'food' => 'grape', 'shape' => 'oval', 'sizes' => $VAR1->[0]{'sizes'} } ];
        But using util's solution, clone solves the problem:
        push(@array,clone($d));
        So, why does it "work" on the first pass (without using clone) and then from there I just get a shallow copy?
      And yet an even better example... why the heck does this work and not the previous examples?
      It only *seems* to work, because you are dumping too little, too often.
      If you add print Dumper($data1); after the close of the foreach, you will see the $VAR1->[0]{'sizes'} back-pointers.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (2)
As of 2024-04-16 23:39 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found