Perl:do-while 遍历 "growing" 数组散列中的键数产生 "extra" 输出
Perl: do-while loop over number of keys in a "growing" Hash of Arrays produces "extra" output
我不确定我是否在标题中说得很清楚,但我的问题是这样的:我有一个 do-while 循环,它接受一个初始化的数组散列 (HoA),计算一个新的维度数组,然后将生成的数组与与每个键的数组关联的数组进行比较(为简单起见,键是数字的……所以最好将其作为数组的数组来执行)。如果某些 crietria 是合适的(例如,新值在特定 "distance" 内),则会为 HoA 生成一个新密钥,并将生成的数组与新密钥一起添加到 HoA。
奇怪的是我用 do-while 循环限制了新键的数量,但有时当我 运行 代码(根本没有做任何更改)时,我得到 "extra" 键。
我的代码在下面,任何帮助都会很棒。
use strict;
use warnings;
use Data::Dumper;
my $PolymerSize=6;
# each monomer/node can bond upto 3 times
my $maxNeighbors=3;
#Store coordinates and number of neighbors for each monomer/node
# (in C would be an array of structs)
my %HoA;
my %BondHoA; #who are my neighbors
my @coordsNeighbors;
my $element; #Iteration dummy variable
my %dist; #temporary distance hash
my $return_flag;
$coordsNeighbors[0]=0; #Xcoord
$coordsNeighbors[1]=0; #YCoord
$coordsNeighbors[2]=0; #ZCoord
$coordsNeighbors[3]=0; #How many bonded neighbors?
#Intialize origin (first node/monomer)
push @{$HoA{0}}, $coordsNeighbors[0];
push @{$HoA{0}}, $coordsNeighbors[1];
push @{$HoA{0}}, $coordsNeighbors[2];
push @{$HoA{0}}, $coordsNeighbors[3];
#Generate new nodes/monomer and "grow" polymer
do{
for(my $j=0;$j<3;$j++){
#generate coords of potent. monomers/node
$coordsNeighbors[$j] = int($PolymerSize*rand());
}
$coordsNeighbors[3]=0;
#loop through existing monomers/nodes
foreach $element ( keys %HoA) {
#if this monomer doesn't have the max bonds proceed
if( ($HoA{$element}[3])!=$maxNeighbors) {
my $tempx=$HoA{$element}[0]-$coordsNeighbors[0];
my $tempy=$HoA{$element}[1]-$coordsNeighbors[1];
my $tempz=$HoA{$element}[2]-$coordsNeighbors[2];
#make hash of L1 distances
$dist{$element} .=abs($tempx)+abs($tempy)+abs($tempz);
}
}
#check if any distance is != 1; no-bond could be made if so
foreach(keys %dist){
if($dist{$_}!=1) {
delete $dist{$_};
}
}
#potential monomer is good, so add to HoA and update bonds
foreach $element (keys %dist){
$HoA{$element}[3]++;
my $newKey=scalar (keys %HoA);
if($newKey!=($PolymerSize-1)){
push @{$HoA{$newKey}}, $coordsNeighbors[0];
push @{$HoA{$newKey}}, $coordsNeighbors[1];
push @{$HoA{$newKey}}, $coordsNeighbors[2];
push @{$HoA{$newKey}}, $coordsNeighbors[3]+1;
push @{$BondHoA{$element}}, "$newKey";
push @{$BondHoA{$newKey}}, "$element";
}
delete $dist{$element};
}
} while((keys %HoA)<$PolymerSize-1);
foreach $element (keys %HoA) {
print "$element \t $HoA{$element}[0] \t $HoA{$element}[1] \t $HoA{$element}[2]\n";
}
此代码背后的总体思路是做一些事情,比如在 3D 中像 DLA(diffusion-limited 聚合体)一样生长聚合物,因此需要满足两点才能使其正常工作:
1) 获得正确数量的单体(上面提到的 HoA 密钥)。
2) 确保没有 monomer-overlaps(没有 L1 距离为 0(曼哈顿距离,因为我们在网格上))。
[编辑]
我显然忘了包括所需的输出(我很抱歉)。
输出应该是这样的:
0 0 0 0
1 1 0 0
2 0 1 0
3 2 0 0
4 2 1 0
5 2 2 0
但我最终得到的是:
0 0 0 0
1 1 0 0
2 0 1 0
3 0 0 0
4 1 1 0
5 0 1 1
6 2 0 0
(有时甚至是第 8 或第 9 个值)
简单修改即可
确保哈希大小为 6
my $newKey=scalar (keys %HoA);
print "newKey<$newKey>\n";
if($newKey !=($PolymerSize-1)){
# changed to
if($newKey <=($PolymerSize-1)){
确保散列的大小为 6
} while((keys %HoA)<$PolymerSize-1);
#change to
} while((keys %HoA)<=$PolymerSize-1);
按照@Schwern 的建议,我回去查看了
foreach $element (keys %dist){ ...
循环并意识到实际上发生的事情是,即使在删除所有与 %dist 散列中的 non-one 值一致的键之后,我在 %dist 散列中可能有超过 1 个成员。然后一个简单的修复是添加一个 "last"
foreach $element (keys %dist){
$HoA{$element}[3]++;
my $newKey=scalar (keys %HoA);
if($newKey!=($PolymerSize-1)){
push @{$HoA{$newKey}}, $coordsNeighbors[0];
push @{$HoA{$newKey}}, $coordsNeighbors[1];
push @{$HoA{$newKey}}, $coordsNeighbors[2];
push @{$HoA{$newKey}}, $coordsNeighbors[3]+1;
push @{$BondHoA{$element}}, "$newKey";
push @{$BondHoA{$newKey}}, "$element";
#here I add a last to break out and go to the next do-while iter.
last
}
然后在 do-while 循环的顶部添加对 undef(%dist) 的调用,以清除它以供再次使用。
此外,在修复此错误后,我返回 cleaned-up 大部分代码,现在在下面为感兴趣的人提供:
#!/usr/bin/perl;
use strict;
use warnings;
use Data::Dumper;
my $PolymerSize=8;
my $maxNeighbors=3; #each monomer/node can bond upto 3 times
my %HoA; #Store coordinates and number of neighbors for each monomer/node (in C would be an array of structs)
my %BondHoA; #who are my neighbors
my @coordsNeighbors;
my $element; #Iteration dummy variable
my %dist; #temporary distance hash
my $selected;
$coordsNeighbors[0]=0; #Xcoord
$coordsNeighbors[1]=0; #YCoord
$coordsNeighbors[2]=0; #ZCoord
$coordsNeighbors[3]=$maxNeighbors; #How many bonded neighbors?
my $tempx;
my $tempy;
my $tempz;
my $tempL1;
#Intialize origin (first node/monomer)
push @{$HoA{0}}, $coordsNeighbors[0];
push @{$HoA{0}}, $coordsNeighbors[1];
push @{$HoA{0}}, $coordsNeighbors[2];
push @{$HoA{0}}, $coordsNeighbors[3];
my $iter=0;
#Generate new nodes/monomer and "grow" polymer
do{
#print "$iter\n";
# $iter++;
undef(%dist);
for(my $j=0;$j<3;$j++){
$coordsNeighbors[$j]=int($PolymerSize*rand()); #generate coords of potent. monomers/node
}
$coordsNeighbors[3]=$maxNeighbors;
foreach $element ( keys %HoA) { #loop through existing monomers/nodes
$tempx=int($HoA{$element}[0])-int($coordsNeighbors[0]);
$tempy=int($HoA{$element}[1])-int($coordsNeighbors[1]);
$tempz=int($HoA{$element}[2])-int($coordsNeighbors[2]);
$tempL1=abs($tempx)+abs($tempy)+abs($tempz);
if($tempL1==1){
$dist{$element} .= $tempL1;
} elsif($tempL1==0){
undef(%dist);
last;
}
}
foreach $element (keys %dist){
if ( ($HoA{$element}[3]>0)){ #potential monomer is good, so add to HoA and update bonds
my $newKey=scalar (keys %HoA);
if($newKey<=($PolymerSize-1)){
$HoA{$element}[3]--;
push @{$HoA{$newKey}}, $coordsNeighbors[0];
push @{$HoA{$newKey}}, $coordsNeighbors[1];
push @{$HoA{$newKey}}, $coordsNeighbors[2];
push @{$HoA{$newKey}}, $coordsNeighbors[3];
push @{$BondHoA{$element}}, "$newKey";
push @{$BondHoA{$newKey}}, "$element";
last;
}
}
}
} while((scalar (keys %HoA))<=$PolymerSize-1);
foreach $element (keys %HoA){
print "$element \t $HoA{$element}[0] \t $HoA{$element}[1] \t $HoA{$element}[2]\n";
}
我不确定我是否在标题中说得很清楚,但我的问题是这样的:我有一个 do-while 循环,它接受一个初始化的数组散列 (HoA),计算一个新的维度数组,然后将生成的数组与与每个键的数组关联的数组进行比较(为简单起见,键是数字的……所以最好将其作为数组的数组来执行)。如果某些 crietria 是合适的(例如,新值在特定 "distance" 内),则会为 HoA 生成一个新密钥,并将生成的数组与新密钥一起添加到 HoA。
奇怪的是我用 do-while 循环限制了新键的数量,但有时当我 运行 代码(根本没有做任何更改)时,我得到 "extra" 键。
我的代码在下面,任何帮助都会很棒。
use strict;
use warnings;
use Data::Dumper;
my $PolymerSize=6;
# each monomer/node can bond upto 3 times
my $maxNeighbors=3;
#Store coordinates and number of neighbors for each monomer/node
# (in C would be an array of structs)
my %HoA;
my %BondHoA; #who are my neighbors
my @coordsNeighbors;
my $element; #Iteration dummy variable
my %dist; #temporary distance hash
my $return_flag;
$coordsNeighbors[0]=0; #Xcoord
$coordsNeighbors[1]=0; #YCoord
$coordsNeighbors[2]=0; #ZCoord
$coordsNeighbors[3]=0; #How many bonded neighbors?
#Intialize origin (first node/monomer)
push @{$HoA{0}}, $coordsNeighbors[0];
push @{$HoA{0}}, $coordsNeighbors[1];
push @{$HoA{0}}, $coordsNeighbors[2];
push @{$HoA{0}}, $coordsNeighbors[3];
#Generate new nodes/monomer and "grow" polymer
do{
for(my $j=0;$j<3;$j++){
#generate coords of potent. monomers/node
$coordsNeighbors[$j] = int($PolymerSize*rand());
}
$coordsNeighbors[3]=0;
#loop through existing monomers/nodes
foreach $element ( keys %HoA) {
#if this monomer doesn't have the max bonds proceed
if( ($HoA{$element}[3])!=$maxNeighbors) {
my $tempx=$HoA{$element}[0]-$coordsNeighbors[0];
my $tempy=$HoA{$element}[1]-$coordsNeighbors[1];
my $tempz=$HoA{$element}[2]-$coordsNeighbors[2];
#make hash of L1 distances
$dist{$element} .=abs($tempx)+abs($tempy)+abs($tempz);
}
}
#check if any distance is != 1; no-bond could be made if so
foreach(keys %dist){
if($dist{$_}!=1) {
delete $dist{$_};
}
}
#potential monomer is good, so add to HoA and update bonds
foreach $element (keys %dist){
$HoA{$element}[3]++;
my $newKey=scalar (keys %HoA);
if($newKey!=($PolymerSize-1)){
push @{$HoA{$newKey}}, $coordsNeighbors[0];
push @{$HoA{$newKey}}, $coordsNeighbors[1];
push @{$HoA{$newKey}}, $coordsNeighbors[2];
push @{$HoA{$newKey}}, $coordsNeighbors[3]+1;
push @{$BondHoA{$element}}, "$newKey";
push @{$BondHoA{$newKey}}, "$element";
}
delete $dist{$element};
}
} while((keys %HoA)<$PolymerSize-1);
foreach $element (keys %HoA) {
print "$element \t $HoA{$element}[0] \t $HoA{$element}[1] \t $HoA{$element}[2]\n";
}
此代码背后的总体思路是做一些事情,比如在 3D 中像 DLA(diffusion-limited 聚合体)一样生长聚合物,因此需要满足两点才能使其正常工作:
1) 获得正确数量的单体(上面提到的 HoA 密钥)。
2) 确保没有 monomer-overlaps(没有 L1 距离为 0(曼哈顿距离,因为我们在网格上))。
[编辑] 我显然忘了包括所需的输出(我很抱歉)。
输出应该是这样的:
0 0 0 0
1 1 0 0
2 0 1 0
3 2 0 0
4 2 1 0
5 2 2 0
但我最终得到的是:
0 0 0 0
1 1 0 0
2 0 1 0
3 0 0 0
4 1 1 0
5 0 1 1
6 2 0 0
(有时甚至是第 8 或第 9 个值)
简单修改即可
确保哈希大小为 6
my $newKey=scalar (keys %HoA);
print "newKey<$newKey>\n";
if($newKey !=($PolymerSize-1)){
# changed to
if($newKey <=($PolymerSize-1)){
确保散列的大小为 6
} while((keys %HoA)<$PolymerSize-1);
#change to
} while((keys %HoA)<=$PolymerSize-1);
按照@Schwern 的建议,我回去查看了
foreach $element (keys %dist){ ...
循环并意识到实际上发生的事情是,即使在删除所有与 %dist 散列中的 non-one 值一致的键之后,我在 %dist 散列中可能有超过 1 个成员。然后一个简单的修复是添加一个 "last"
foreach $element (keys %dist){
$HoA{$element}[3]++;
my $newKey=scalar (keys %HoA);
if($newKey!=($PolymerSize-1)){
push @{$HoA{$newKey}}, $coordsNeighbors[0];
push @{$HoA{$newKey}}, $coordsNeighbors[1];
push @{$HoA{$newKey}}, $coordsNeighbors[2];
push @{$HoA{$newKey}}, $coordsNeighbors[3]+1;
push @{$BondHoA{$element}}, "$newKey";
push @{$BondHoA{$newKey}}, "$element";
#here I add a last to break out and go to the next do-while iter.
last
}
然后在 do-while 循环的顶部添加对 undef(%dist) 的调用,以清除它以供再次使用。
此外,在修复此错误后,我返回 cleaned-up 大部分代码,现在在下面为感兴趣的人提供:
#!/usr/bin/perl;
use strict;
use warnings;
use Data::Dumper;
my $PolymerSize=8;
my $maxNeighbors=3; #each monomer/node can bond upto 3 times
my %HoA; #Store coordinates and number of neighbors for each monomer/node (in C would be an array of structs)
my %BondHoA; #who are my neighbors
my @coordsNeighbors;
my $element; #Iteration dummy variable
my %dist; #temporary distance hash
my $selected;
$coordsNeighbors[0]=0; #Xcoord
$coordsNeighbors[1]=0; #YCoord
$coordsNeighbors[2]=0; #ZCoord
$coordsNeighbors[3]=$maxNeighbors; #How many bonded neighbors?
my $tempx;
my $tempy;
my $tempz;
my $tempL1;
#Intialize origin (first node/monomer)
push @{$HoA{0}}, $coordsNeighbors[0];
push @{$HoA{0}}, $coordsNeighbors[1];
push @{$HoA{0}}, $coordsNeighbors[2];
push @{$HoA{0}}, $coordsNeighbors[3];
my $iter=0;
#Generate new nodes/monomer and "grow" polymer
do{
#print "$iter\n";
# $iter++;
undef(%dist);
for(my $j=0;$j<3;$j++){
$coordsNeighbors[$j]=int($PolymerSize*rand()); #generate coords of potent. monomers/node
}
$coordsNeighbors[3]=$maxNeighbors;
foreach $element ( keys %HoA) { #loop through existing monomers/nodes
$tempx=int($HoA{$element}[0])-int($coordsNeighbors[0]);
$tempy=int($HoA{$element}[1])-int($coordsNeighbors[1]);
$tempz=int($HoA{$element}[2])-int($coordsNeighbors[2]);
$tempL1=abs($tempx)+abs($tempy)+abs($tempz);
if($tempL1==1){
$dist{$element} .= $tempL1;
} elsif($tempL1==0){
undef(%dist);
last;
}
}
foreach $element (keys %dist){
if ( ($HoA{$element}[3]>0)){ #potential monomer is good, so add to HoA and update bonds
my $newKey=scalar (keys %HoA);
if($newKey<=($PolymerSize-1)){
$HoA{$element}[3]--;
push @{$HoA{$newKey}}, $coordsNeighbors[0];
push @{$HoA{$newKey}}, $coordsNeighbors[1];
push @{$HoA{$newKey}}, $coordsNeighbors[2];
push @{$HoA{$newKey}}, $coordsNeighbors[3];
push @{$BondHoA{$element}}, "$newKey";
push @{$BondHoA{$newKey}}, "$element";
last;
}
}
}
} while((scalar (keys %HoA))<=$PolymerSize-1);
foreach $element (keys %HoA){
print "$element \t $HoA{$element}[0] \t $HoA{$element}[1] \t $HoA{$element}[2]\n";
}