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

Hi Monks, I have a very weird problem. Basically, I am trying to update a "cell" in an array of array. e.g. @unique_manufacturer_model->[$i][12]++ Somehow, the exact row/column of another cell (in another array) is also being updated with the same value. I've tried changing the name of the array but does'nt work. The routine printing out the result is confirmed working fine. I just ca'nt understand why updating this array will affect another array of a different name. As you can see below, I do'nt know how the result 5,36,1 can appear in the other array. Here's the code snippets:
for my $i (0 .. $#unique_manufacturer_model) { for my $j (0 .. $#unique_terminal_id) { if ( (@unique_manufacturer_model->[$i][9] eq @unique_terminal_ +id->[$j][9]) and (@unique_manufacturer_model->[$i][10] eq @unique_ter +minal_id->[$j][10]) ) { if (@unique_manufacturer_model->[$i][12] eq "") { @unique_manufacturer_model->[$i][12] = 1; } else { @unique_manufacturer_model->[$i][12]++; } } } } &checkpoint(9,10,12,@unique_manufacturer_model); &checkpoint(10,11,12,@unique_manufacturer_model_version); And here's the output: [root@localhost cron]# perl probe_cron.pl 1) Nokia | N77 | 5 2) Nokia | Nokia N96 | 36 3) | | 1 1) N77 | [V 3.0747.2.0.3|22-11-2007|RM-194] | 5 2) Nokia N96 | [10.045|31-07-08|RM-247|(C) Nokia N96] | 36 3) Nokia N96 | [v 0.0804.X.0.032|06-02-08|RM-247|(C) Nokia N96] | 4) | [] | 1 5) N77 | [V 3.0827.22.0.1-RD|04-07-2008|RM-194] |

Replies are listed 'Best First'.
Re: Updating 1 array affects the other array
by llancet (Friar) on Sep 02, 2008 at 06:36 UTC
    I think your problem seems not being caused by the code you show us. It is probably caused in the construction the arrays. You might have used the method below:
    $array2[$n] = $array1[$n];
    Because your two arrays are complex, this does not copy the structure and content, but only copy the corresponding reference. So the value $n in @array2 actually points to the value $n in @array1.
    In addition, while asking questions, please make your code more refined, for example:
    for my $i (0..$#array1) { for my $j (0..$#array2) { # do something } }
Re: Updating 1 array affects the other array
by wfsp (Abbot) on Sep 02, 2008 at 07:31 UTC
    ...a "cell" in an array of array. e.g. @unique_manufacturer_model->[$i][12]++
    (my emphasis)

    A couple of points. The @ should be $ (think singlular, scalar, $) and you don't need the arrow (you have an array and the arrow is trying to dereference a reference to an array). If you had strict and warnings enabled Perl would have complained about it.

    It would be well worth straightening out these snags first. Perl will help you if you turn on strict and warnings. :-)

    update: fixed typo

Re: Updating 1 array affects the other array
by Anonymous Monk on Sep 02, 2008 at 06:50 UTC
    I've tried changing the name of the array but does'nt work.I just ca'nt understand why updating this array will affect another array of a different name

    Because a name don't mean much when you're modifying references. Example

    my @foo = 1 .. 4; my @bar; my $someReference = \@foo; $bar[0] = $someReference; $bar[1] = \@foo; $bar[2] = $foo[2]; use Data::Dumper; print Dumper( \@bar ),"\n"; $bar[0][0]='change'; $bar[2] .= ' foo '; print " bar[0][0] ", $bar[0][0], "\n"; print " bar[1][0] ", $bar[1][0], "\n"; print Dumper( \@bar ),"\n"; __END__ $VAR1 = [ [ 1, 2, 3, 4 ], $VAR1->[0], 3 ]; bar[0][0] change bar[1][0] change $VAR1 = [ [ 'change', 2, 3, 4 ], $VAR1->[0], '3 foo ' ];
    Make a change to $bar[0][0], and you're also changing $bar[1][0] because they are one and the same. It doesn't matter if you rename @bar to @barbar if you still asing $bar[0] and $bar[1] the same reference.

    See perldata,perlref,perldsc... and perlmonks own Tutorials

      Hi everyone. Thanks for the pointers. I clean up things like removing the arrows. So far it has not work, because there's this part of the code, where I suspect is wrong, but I'm not skilled enough to think of an alternative.
      my %seen_values; my @unique_terminal_id = grep { !($seen_values{$_->[4]}++) } @temp_ope +n_single; my %seen_values; my @unique_manufacturer_model = grep { !($seen_values{$_->[9]}{$_->[10 +]}++) } @unique_terminal_id; my %seen_values; my @unique_manufacturer_model_version = grep { !($seen_values{$_->[9]} +{$_->[10]}{$_->[11]}++) } @unique_terminal_id;
      This portion of code is where I have declared the arrays and just before I encounter the problem. Basically, what I am trying to do is grep unique column pair in a table(array of array) and store them into a new table. I managed to get what I wanted (e.g. the unique pairs), but I ca'nt quite see how it ended up cross-referencing to another array. Thanks!
        ...but I ca'nt quite see how it ended up cross-referencing to another array.
        Let me repeat, it is because you are storing references. If you want copies, use Storable qw(dclone); Observe
        my $ref = [ 1,2]; my $another = [3,4]; my @foo = ( $ref, $another); my @bar = $foo[1]; die $bar[0][1]; __END__ 4 at - line 6.
        get it?
Re: Updating 1 array affects the other array
by llancet (Friar) on Sep 02, 2008 at 10:47 UTC
    the trap of cross-reference happens like this:
    firstly you have an aoa:
    @array1=( [1,2,3], [4,5,6], [7,8,9] );
    then if you make this:
    $array2[1]=$array1[1]
    and change value in $array1
    $array1[1][0]='something';
    you will get
    print $array2[1][0]; # shows 'something'
    the $array21 is virtually have the same memory space with corresponding value in @array1, because the thing stored in $array1 is actually a reference to the anonymous list 4,5,6. So, what you give to array2 is the same reference, but not the values.
      Hi, thanks for the explanation. I understand your explanation, but I've checked thru my codes but ca'nt see such mistake being committed. The only (write) operations I've done to the arrays (prior to discovering the problem) is shown below. What I am trying to do is to remove duplicate entries (based on certain column combinations) and store them in a new array (those with the "unique" prefix). The "cross-referencing" seems to have been committed here.
      my %seen_values; my @unique_terminal_id = grep { !($seen_values{$_->[4]}++) } @temp_ope +n_single; my %seen_values; my @unique_manufacturer_model = grep { !($seen_values{$_->[9]}{$_->[10 +]}++) } @unique_terminal_id; my %seen_values; my @unique_manufacturer_model_version = grep { !($seen_values{$_->[9]} +{$_->[10]}{$_->[11]}++) } @unique_terminal_id;
        As other people have mentioned, what you're copying are references (as indicated by the de-referencing arrows that you're using in the greps). Namely, your array @temp_open_single is, presumably, an array of arrayrefs.

        Let's say that the first arrayref is pointing to the array at 0x18045c0, and that that array passes the test in the grep for @unique_terminal_id. Then @unique_terminal_id also contains a reference to the array at 0x18045c0. Let's suppose further that that array also passes the test in the grep for @unique_manufacturer_model. Then @unique_manufacturer_model also contains a reference to the—exact same!—array at 0x18045c0. It is copying the reference, not the referent.

        That means that, when you refer to $unique_terminal_id[0][0] or to $unique_manufacturer_model[0][0], in either case you're just looking at the entry at index 0 of the single array at 0x18045c0. After you change that single array in one place, the changes will still be visible even if you look at it from another location. As others have mentioned, you need something like Storable's dclone function (which makes a 'deep clone') will allow you to avoid this difficulty.