Pau RS
Pau RS

Reputation: 86

Why does the second array gets modified?

I just want to assign the value of the AB array to the last position of the ABU array.

$ABU->[1][-1][1] = $AB->[1][$i][1];

And every time this assignation occurs, the AB array gets modified.

for ($i = 1; $i < $lenghtf; $i++) {
        if ($ABU->[1][-1][1] < $AB->[1][$i][0]) {
            push (@{$ABU->[1]}, $AB->[1][$i]);
        } elsif ($ABU->[1][-1][1] < $AB->[1][$i][1]){
            $ABU->[1][-1][1] = $AB->[1][$i][1];
        }
    }

If I do

print Dumper ($AB[1]);

before the loop and

print Dumper {ABU => $ABU, AB => $AB};

after the loop, I get this output:

![enter image description here][1]

After people's answers, I have realised that the problem may be when I assign the first value to ABU[1] before the loop:

push (@{$ABU->[1]}, $AB->[1][0]);

If I do print with dumper before the loop:

enter image description here

I've tried to change that firs asignation syntax:

push (@{$ABU->[1]}, @{$AB->[1][0]});

And then the Dumper looks better:

enter image description here

The problem now is that I don't know why when I run the for loop it complains in the first if line:

if ($ABU->[1][-1][1] < $AB->[1][$i][0]) {

with this STDERR:

Can't use string ("15") as an ARRAY ref while "strict refs"

Upvotes: 1

Views: 107

Answers (2)

Hynek -Pichi- Vychodil
Hynek -Pichi- Vychodil

Reputation: 26131

The problem is this line

push (@{$ABU->[1]}, $AB->[1][$i]);

Here you clearly insert a reference to the array. It will be seen at result of print Dumper {ABU => $ABU, AB => $AB}; which is missing in your question. But it can be seen in the next image.

image

See this $VAR->{ABU}[1][0]. After few cycles, you will end up with multiple references to the same array.

For your data format, you can do

push @{$ABU->[1]}, [@{$AB->[1][$i]}];

But using some cloning routine would be more robust (immune to the feature code changes which inevitably come with time).

use Storable qw(dclone);
push @{$ABU->[1]}, dclone($AB->[1][$i]);

BTW your code could be written

use Storable qw(dclone);
for my $ab_row (@{$AB->[1]}) {
    my $last_abu_row = $ABU->[1][-1];
    if ($last_abu_row->[1] < $ab_row->[0]) {
        push @{$ABU->[1]}, dclone($ab_row);
    } elsif ($last_abu_row->[1] < $ab_row->[1]) {
        $last_abu_row->[1] = $ab_row->[1];
    }
}

Edit:

The expression push @{$ABU->[1]}, [@{$AB->[1][$i]}];:

$AB->[1][$i] is array reference

@{$AB->[1][$i]} is content of array refrenced by $AB->[1][$i]

[@{$AB->[1][$i]}] is array reference to fresh new array with content of array referenced by $AB->[1][$i]. It is shorthand of:

do {
    my @array;                # fresh new array
    @array = @{$AB->[1][$i]}; # Here you copy content of array
    \@array;                  # return reference to the new array
}

Then you push it to the array referenced by $ABU->[1]. After this statement $ABU->[1][-1] contains array reference to the new array with content copied from array referenced by $AB->[1][$i].

In contrast push @{$ABU->[1]}, $AB->[1][$i];

$AB->[1][$i] is array reference

which you push into the array referenced by $ABU->[1]. So you push array reference referencing the original array. In other words, after the statement $ABU->[1][-1] = $AB->[1][$i], the same array reference.

The third statement push @{$ABU->[1]}, @{$AB->[1][$i]}; will push content of array referenced by $AB->[1][$i]. It means you don't add one new element to the array referenced by $ABU->[1] but same amount of elements as @{$AB->[1][$i]} contains. It breaks reference but doesn't do what you want. You could fix it this way:

push @{$ABU->[1]}, [];
push @{$ABU->[1][-1]}, @{$AB->[1][$i]};

but it is less elegant way of writing push @{$ABU->[1]}, [@{$AB->[1][$i]}];.

Upvotes: 3

ulix
ulix

Reputation: 373

You are non showing so much code. Maybe both $ABU and $AB are references to same array.

Upvotes: 1

Related Questions