对数组的修改也会更改其他数组
Modifications to array also change other array
我在 Perl 中有两个全局多维数组 @p
和 @p0e
。这是遗传算法的一部分,我想在其中保存从 @p
到 @p0e
的某些密钥。然后对 @p
进行修改。有几个对 @p
进行修改的子例程,但是有一个特定的子例程有时(不是每次迭代)对 @p
的修改也会导致 @p0e
被修改(它接收相同的键)虽然 @p0e
不应该受到影响。
# 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]);
}
}
}
}
我想也许我以某种方式创建了对原始数组的引用而不是副本,但是因为这种意外行为不会在每次迭代中发生,所以不应该是这种情况。
那是因为它是一个数组的数组。第一级数组只存储对内部数组的引用,如果你修改内部数组,它在两个数组中都会改变——它们都引用同一个数组。 Clone 深拷贝而不是创建浅拷贝。
我认为你的问题可能是这样的:
$p0e[$i] = $p[$f{"rank"}{$r}]; # save chromosome
因为看起来@p
是一个多维数组
问题是 - perl 'does' 多维数组的方式是通过引用数组。所以如果你复制一个内部数组,你通过引用来这样做。
例如:
#!c:\Strawberry\perl\bin
use strict;
use warnings;
use Data::Dumper;
my @list = ( [ 1, 2, 3 ],
[ 4, 5, 6 ],
[ 7, 8, 9 ], );
print Dumper \@list;
my @other_list;
push ( @other_list, @list[0,1] ); #make a sub list of two rows;
print Dumper \@other_list;
### all looks good.
## but if we:
print "List:\n";
print join ("\n",@list),"\n";
print "Other List:\n";
print join ("\n", @other_list),"\n";
$list[1][1] = 9;
print Dumper \@other_list;
您会看到,通过更改 @list
中的一个元素,我们也会修改 @other_list
- 如果我们只是 print
他们,我们会得到:
List:
ARRAY(0x2ea384)
ARRAY(0x12cef34)
ARRAY(0x12cf024)
Other List:
ARRAY(0x2ea384)
ARRAY(0x12cef34)
注意重复的数字 - 这意味着您有相同的参考。
解决此问题的最简单方法是明智地使用 []
:
push ( @other_list, [@{$list[0]}], [@{$list[1]}] ); #make a sub list of two rows;
然后这将插入包含列表中取消引用的元素的匿名数组(新数组)。
尽管我们正在处理 - 请打开 strict
和 warnings
。在漫长的 运行 中,它们会为您省去很多痛苦。
$j = $f{"rank"}{$r};
$p0e[$i] = $p[$j];
$p[$j]
是一个数组reference,你可以认为它指向特定内存地址的特定数据列表。对 $p0e[$i]
的赋值也告诉 Perl 让 @p0e
的第 $i
行也引用相同的内存块。所以当你稍后对 $p0e[$i][$k]
进行更改时,你会发现 $p[$j][$k]
的值也发生了变化。
要解决此问题,您需要分配 $p[$j]
的 副本。这是您可以执行此操作的一种方法:
$p0e[$i] = [ @{$p[$j]} ];
@{$p[$j]}
引用数组引用并且 [...]
为它创建一个新的引用,所以在这条语句之后 $p0e[$i]
将具有与 [=12= 相同的内容和相同的值] 但指向不同的内存块。
我在 Perl 中有两个全局多维数组 @p
和 @p0e
。这是遗传算法的一部分,我想在其中保存从 @p
到 @p0e
的某些密钥。然后对 @p
进行修改。有几个对 @p
进行修改的子例程,但是有一个特定的子例程有时(不是每次迭代)对 @p
的修改也会导致 @p0e
被修改(它接收相同的键)虽然 @p0e
不应该受到影响。
# 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]);
}
}
}
}
我想也许我以某种方式创建了对原始数组的引用而不是副本,但是因为这种意外行为不会在每次迭代中发生,所以不应该是这种情况。
那是因为它是一个数组的数组。第一级数组只存储对内部数组的引用,如果你修改内部数组,它在两个数组中都会改变——它们都引用同一个数组。 Clone 深拷贝而不是创建浅拷贝。
我认为你的问题可能是这样的:
$p0e[$i] = $p[$f{"rank"}{$r}]; # save chromosome
因为看起来@p
是一个多维数组
问题是 - perl 'does' 多维数组的方式是通过引用数组。所以如果你复制一个内部数组,你通过引用来这样做。
例如:
#!c:\Strawberry\perl\bin
use strict;
use warnings;
use Data::Dumper;
my @list = ( [ 1, 2, 3 ],
[ 4, 5, 6 ],
[ 7, 8, 9 ], );
print Dumper \@list;
my @other_list;
push ( @other_list, @list[0,1] ); #make a sub list of two rows;
print Dumper \@other_list;
### all looks good.
## but if we:
print "List:\n";
print join ("\n",@list),"\n";
print "Other List:\n";
print join ("\n", @other_list),"\n";
$list[1][1] = 9;
print Dumper \@other_list;
您会看到,通过更改 @list
中的一个元素,我们也会修改 @other_list
- 如果我们只是 print
他们,我们会得到:
List:
ARRAY(0x2ea384)
ARRAY(0x12cef34)
ARRAY(0x12cf024)
Other List:
ARRAY(0x2ea384)
ARRAY(0x12cef34)
注意重复的数字 - 这意味着您有相同的参考。
解决此问题的最简单方法是明智地使用 []
:
push ( @other_list, [@{$list[0]}], [@{$list[1]}] ); #make a sub list of two rows;
然后这将插入包含列表中取消引用的元素的匿名数组(新数组)。
尽管我们正在处理 - 请打开 strict
和 warnings
。在漫长的 运行 中,它们会为您省去很多痛苦。
$j = $f{"rank"}{$r};
$p0e[$i] = $p[$j];
$p[$j]
是一个数组reference,你可以认为它指向特定内存地址的特定数据列表。对 $p0e[$i]
的赋值也告诉 Perl 让 @p0e
的第 $i
行也引用相同的内存块。所以当你稍后对 $p0e[$i][$k]
进行更改时,你会发现 $p[$j][$k]
的值也发生了变化。
要解决此问题,您需要分配 $p[$j]
的 副本。这是您可以执行此操作的一种方法:
$p0e[$i] = [ @{$p[$j]} ];
@{$p[$j]}
引用数组引用并且 [...]
为它创建一个新的引用,所以在这条语句之后 $p0e[$i]
将具有与 [=12= 相同的内容和相同的值] 但指向不同的内存块。