Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Array of Arrays: why is "$VAR1->[0][1]" and the like embedded within?

by corenth (Monk)
on Jun 11, 2018 at 02:58 UTC ( [id://1216360]=perlquestion: print w/replies, xml ) Need Help??

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

EDIT:

After reading the responses to my post, I've come to two tentative conclusions: 1) I have only a loose grasp of how references work in Perl. It's obvious I have a lot to learn on the subject. 2) In this case, I'm mistaking output for content (Data::Dumper does not represent the reference structure's content in the way I imagined). 3) This is frustrating but fun as hell.


Here's my edited code that gives me what I want (thank you all for helping me with this):
sub inc{ my $ref=shift; my $span=shift; $span?($span--):($span=1); my @b=map{ clone([@$ref[$_-$span..$_]]) }($span..$#$ref); \@b } sub clone{#clone references my $ref=shift; my@array=map{ ref($_)?clone($_):$_ }@$ref; \@array } my@b=(1..5); my $c = inc(inc(\@b)); print Dumper $c;
Which produces:
$VAR1 = [ [ [ 1, 2 ], [ 2, 3 ] ], [ [ 2, 3 ], [ 3, 4 ] ], [ [ 3, 4 ], [ 4, 5 ] ] ];
Woohoo!

ORIGINAL POST:

I have come across a strange thing. If I run the following code with an array of scalars, then I get what I expect. E.g.,
@a = (1,2,3,4,5,6); increment(\@a); #produces tuples of: [1,2],[2,3],[3,4],[4,5],[5,6] #yay!!
But, I want to run increment() with arrays of arrays. But, the result is all sorts of funky. Here's Data::Dumper output:
$VAR1 = [ [ [ 1, 2 ], [ 2, 3 ] ], [ $VAR1->[0][1], [ 3, 4 ] ], [ $VAR1->[1][1], [ 4, 6 ] ] ];
I'm using the following test code:
my @a = (1,2,3,4,6); print Dumper increment(increment(\@a)); sub increment{ my $d=shift; my @b; for my $i (1..$#$d){ my @a = @$d[$i-1..$i]; push @b,\@a; } \@b }
The output is half-right --the second part of each tuple is itself a tuple (and is what's expected). But, what's with the first part of each tupple? The "$VAR->[n][1]"

I am flummoxed.


Thanks much for whatever advice you might have.



$state{tired}?sleep(40):eat($food);

Replies are listed 'Best First'.
Re: Array of Arrays: why is "$VAR1->[0][1]" and the like embedded within?
by NetWallah (Canon) on Jun 11, 2018 at 03:51 UTC
    The parameter passed to the second call to "increment" is the AOA consisting of the tuples resulting from the first call.

    Since your code that creates @a basically references elements of existing tuples (which now are references), perl does not create NEW references .. it uses existing addresses of these items.

    This is what Dumper tries to show you - some elements reference things inside yourself!

    The actual values generated are indeed proper tuples the way you expect .. they just happen to be references to existing stuff.

    FYI - the "increment" sub could be condensed to a single statement:

    return [ map {[$d->[$_-1],$d->[$_]]} 1..$#$d ];

                    Memory fault   --   brain fried

      ++NetWallah.

      corenth: You can visualise what NetWallah said by writing your own display loop:

      use strict; use warnings; use Data::Dumper; my @a = (1, 2, 3, 4, 6); my $y = increment(increment(\@a)); for my $j (@$y) { print "[\n"; for my $k (@$j) { print " $k: @$k\n"; } print "]\n"; } sub increment ...

      Output:

      14:12 >perl 1896_SoPW.pl [ ARRAY(0x1db5610): 1 2 ARRAY(0x1d284d8): 2 3 ] [ ARRAY(0x1d284d8): 2 3 ARRAY(0x1d28640): 3 4 ] [ ARRAY(0x1d28640): 3 4 ARRAY(0x1d28a00): 4 6 ] 14:12 >

      Hope that helps,

      Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

        or .. it may be easier to dump the elements of the output:
        print Dumper $_ for @{ increment(increment(\@a)) }; # Output: [ [ 1, 2 ], [ 2, 3 ] ] [ [ 2, 3 ], [ 3, 4 ] ] [ [ 3, 4 ], [ 4, 6 ] ]

                        Memory fault   --   brain fried

        I kind of get it, but it's still hard for me to visualize. I'm going to play with this along with everyone's code on this thread. It's a must that I get my head around it.
        $state{tired}?sleep(40):eat($food);
      Ah. My thoughts went that way, but I had a hard time visualizing the issue. I'll be thinking on it a bit.
      $state{tired}?sleep(40):eat($food);
Re: Array of Arrays: why is "$VAR1->[0][1]" and the like embedded within?
by haukex (Archbishop) on Jun 11, 2018 at 08:40 UTC

    As the others have said, it's because those array elements are referencing the same data structure. A simplified version demonstrating this:

    use Data::Dumper; my $aref = ['x','y']; my @a = ($aref, $aref); print Dumper(\@a); __END__ $VAR1 = [ [ 'x', 'y' ], $VAR1->[0] ];

    I hope it's clear that both elements of @a are referring to the same anonymous array, and that's what Data::Dumper is trying to say with $VAR1->[0]: "this element of the array is the same as the first element of the array reference $VAR1".

    Note: Unfortunately, the above syntax, when evaled, does not produce the same data structure, because a data structure can't actually reference itself this way - remember that Data::Dumper is a debugging tool. But if you need it, you can get Data::Dumper to output something that can be evaled if you use its Purity option:

    use Data::Dumper; my $aref = ['x','y']; my @a = ($aref, $aref); $Data::Dumper::Purity=1; print Dumper(\@a); __END__ $VAR1 = [ [ 'x', 'y' ], [] ]; $VAR1->[1] = $VAR1->[0];

    This kind of data structure could maybe become an issue if you modify elements in the nested data: In the above example, if I modify $a[0][0], then $a[1][0] will change too, since it's the same anonymous array. But if the rest of the code in your program is only reading this data structure, not modifying it, you won't notice the difference in this regard (Update: code that cares about whether two references are pointing to the same data structure might, like we're seeing here with Dumper).

    If you do need all elements of the nested data structure to be different, one way to do that is to use something like Storable's dclone to make a deep copy of the data structures. (There are other ways of course, especially if you know the structure of your input data, but this one has the advantage of being able to copy almost any nested data structure.)

    use Data::Dumper; use Storable qw/dclone/; my @a = (1,2,3,4,6); $Data::Dumper::Indent=0; print Dumper(increment(increment(\@a))), "\n"; sub increment{ my $d = shift; my @b; for my $i (1..$#$d){ my @a = @$d[$i-1..$i]; push @b, dclone \@a; } return \@b; } __END__ $VAR1 = [[[1,2],[2,3]],[[2,3],[3,4]],[[3,4],[4,6]]];

    BTW, I think Data::Dump represents these data structures a bit more nicely (and, in a way that can be evaled back into Perl better, if need be):

    use Data::Dump; my $aref = ['x','y']; my @a = ($aref, $aref); dd \@a; __END__ do { my $a = [["x", "y"], 'fix']; $a->[1] = $a->[0]; $a; }

    Also, if you want Data::Dumper to display these kinds of data structures as if there were no such references, you can use its Deepcopy option:

    use Data::Dumper; $Data::Dumper::Deepcopy = 1; $Data::Dumper::Indent = 0; my $aref = ['x','y']; my @a = ($aref, $aref); print Dumper(\@a), "\n"; __END__ $VAR1 = [['x','y'],['x','y']];

    But remember this affects the output only, the references haven't changed. This may lead to confusion if you change one element, and another element appears to "magically" change.

      The simplified code. . . .
      use Data::Dumper; my $aref = ['x','y']; my @a = ($aref, $aref); print Dumper(\@a); __END__ $VAR1 = [ [ 'x', 'y' ], $VAR1->[0] ];
      . . . . is nifty in that it strips out a lot of material that tends to confuse things for me.
      
      EDIT: I forgot about your dclone and Data::Dump mentions. I'm going to dig into those.
      
      
      $state{tired}?sleep(40):eat($food);

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (3)
As of 2024-04-26 02:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found