Perl:do-while循环遍历"增长" Hash of Arrays产生"额外"产量

时间:2015-12-31 21:18:40

标签: perl hashmap perl-data-structures

我不确定我是否在标题中完全清楚了,但我的问题是这样的:我有do-while循环,它接受一个初始化的数组散列(HoA),计算一个新的维数组,然后将生成的数组与每个键的数组相关联的数组进行比较(为简单起见,键是数字的...所以最好这样做就像数组一样)。如果某些crietria适合(例如,新值在特定的"距离"内),则为HoA生成新密钥,并且使用新密钥将生成的阵列添加到HoA。

奇怪的是,我使用do-while循环限制了新键的数量,但有时当我运行代码时(根本没有进行任何更改),我得到了#34;额外的"密钥。

我的代码如下,任何帮助都会很棒。

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(扩散限制聚合体)这样的聚合物,所以有两件事情需要它才能正常工作:

1)获得正确数量的单体(上面提到的HoA键)。

2)确保没有单体重叠(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个值)

2 个答案:

答案 0 :(得分:0)

按照@Schwern的建议,我回去看了

foreach $element (keys %dist){ ...

循环并意识到确实发生的事情是,即使删除了所有与%dist哈希值中的非一个值一致的键,我也可以在%dist哈希中拥有多个成员。然后一个简单的修复是添加“最后一个”

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)的调用,以清除它以便再次使用。

此外,在修复此错误后,我回过头来清理了大部分代码,现在为感兴趣的人提供了以下内容:

#!/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";
}

答案 1 :(得分:-1)

一个简单的修改就可以了

确保散列大小为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);