Search code examples
arraysperlsubroutine

Modifications to array also change other array


I have two global multidimensional arrays @p and @p0e in Perl. This is part of a genetic algorith where I want to save certain keys from @p to @p0e. Modifications are then made to @p. There are several subroutines that make modifications to @p, but there's a certain subroutine where on occasion (not on every iteration) a modification to @p also leads to @p0e being modified (it receives the same keys) although @p0e should not be affected.

# this is the sub where part of @p is copied to @p0e
sub saveElite {
    @p0e = (); my $i = 0;

    foreach my $r (sort({$a<=>$b} keys $f{"rank"})) {
        if ($i<$elN) {
            $p0e[$i] = $p[$f{"rank"}{$r}]; # save chromosome
        }
        else {last;}
        $i++;
    }
}

# this is the sub that then sometimes changes @p0e
sub mutation {
    for (my $i=0; $i<@p; $i++) {
        for (my $j=0; $j<@{$p[$i]}; $j++) {
            if (rand(1)<=$mut) { # mutation
                $p[$i][$j] = mutate($p[$i][$j]);
            }
        }
    }
}

I thought maybe I'd somehow created a reference to the original array rather than a copy, but because this unexpected behaviour doesn't happen on every iteration this shouldn't be the case.


Solution

  • $j = $f{"rank"}{$r};
    $p0e[$i] = $p[$j];
    

    $p[$j] is an array reference, which you can think of as pointing to a particular list of data at a particular memory address. The assignment to $p0e[$i] also tells Perl to let the $i-th row of @p0e also refer to that same block of memory. So when you later make a change to $p0e[$i][$k], you'll find the value of $p[$j][$k] has changed too.

    To fix this, you'll want to assign a copy of $p[$j]. Here is one way you can do that:

    $p0e[$i] = [ @{$p[$j]} ];
    

    @{$p[$j]} deferences the array reference and [...] creates a new reference for it, so after this statement $p0e[$i] will have the same contents with the same values as $p[$j] but point to a different block of memory.