【问题标题】:Perl: Assigning References to Array Elements in a Foreach LoopPerl:在 Foreach 循环中分配对数组元素的引用
【发布时间】:2011-05-13 18:24:19
【问题描述】:

我真的很想自己解决这个问题,但是我的脸现在因为不断地撞到这堵砖墙而受伤。

我正在尝试加载 9 个文本文件,每个文件由 7 行 7 个字符的矩阵组成,由空格分隔,然后将每个引用的矩阵保存到数组中的一个元素中。我正在阅读每个文件都很好,但是当我访问我的数组时,所有元素都是相同的。我一直在寻找解决方案,但我的问题在任何地方都没有得到解答,或者(更有可能)我不理解答案。这是我的代码的问题部分:

my @boardarray = (1, 2, 3, 4, 5, 6, 7, 8, 9);
sub LoadBoards {
    my (@board, $infile, @allboards);
    my $i = 1;
    @allboards = @boardarray;
    foreach (@allboards) {
        my $infile = "board" . $i . "\.brd";
        open FILE, "< $infile" or die $!;
        my $line = 0;
        while (<FILE>) {
            chomp $_;
            my @chars = split (/ /,$_);
            $board[$line] = [@chars];
            $line++;
        }
    my $tempboard = \@board;
        DisplayOneBoard($tempboard); print ("\n");              #Test A
    $boardarray[$i-1] = \@board;                                #Problem line?
        DisplayOneBoard($boardarray[$i-1]); print ("\n");       #Test B
        DisplayOneBoard($boardarray[0]); print ("\n----\n");    #Test C
    $i++;
    }
}

-我尝试将变量分配为 @boardarray 的元素,但没有任何变化。
-我在 foreach 循环中使用 @boardarray 并将其更改为复制的 @allboards 没有任何改进。
我希望“测试 A”和“测试 B”行是相同的,并且“测试 C”行保持我加载的第一个矩阵。但是,每次迭代所有三个都是相同的。
(对于迭代 1,它们都是矩阵 1。对于迭代 2,它们都是矩阵 2,等等。)
最后,所有元素都是完全相同的矩阵(矩阵 9)。

我们将不胜感激。谢谢。

【问题讨论】:

  • 我没有看到你在这段代码的任何地方更新$i
  • 我在 foreach 循环的最底部做了一个$i++

标签: arrays perl reference foreach


【解决方案1】:

问题是您每次循环都在重复使用相同的 @board。当您将对该板的引用推送到@boardarray 时,您每次都推送指向相同@board 的引用。修复很简单,只需将my @board 移动到foreach 循环的内部即可;这每次都会创建一个新的@board

【讨论】:

    【解决方案2】:

    通过进一步分解代码并使用数组作为堆栈和 push/pop,您可能会获得更好的运气:

    sub load_file {
        my ($filename) = @_;
        open my $file, '<', $filename or die $!;
        my @array;
        while (<$file>) {
            chomp $_;
            my @chars = split (/ /,$_);
            push @array, \@chars;    ### adds a reference to the char line 
                                     ### array to the end of the array
        }
        return \@array;              ### return a ref to the 2-d array
    }
    
    sub load_files {
        my ($num) = @_;
        my %boards;     ### A hash, so we can refer to loaded arrays
                        ### with a string ID
    
        for my $filenum ( 1 .. $num ) {
             my $filename = "board" . $filenum . "\.brd";
             $boards{$filenum} = load_file($filename);
        }
    
        return \%boards;   ### return a ref to the hash of 2-d arrayrefs
    }
    
    ### use it now...
    my $boards = load_files(9); ### load 9 files.
    
    DisplayOneBoard($boards->{6}); ### dereference our hashref, pass board in
                                   ### key '6'to be displayed
    

    【讨论】:

    • 谢谢。我不得不更改第一个子中的这一行:open FILE, '&lt;', $filename or die $!;,第二个子中的这一行:my $filename = "board" . $filenum . "\.brd";,它就像一个魅力。
    • 谢谢——我已经更正了代码。重新打开文件,通常最好的做法是使用词法文件句柄而不是 glob(即标量),因为它可以在 subs 之间传递,并且您可以获得其他一些隐含的好处,例如文件句柄在它时自动关闭超出范围。因此,当您使用while (&lt;$file&gt;) ... 阅读时,open $file ... 将起作用。 filenum 错误是懒惰的复制 :)
    • 我还注意到这使元素 0 为空。一个简单的改变也解决了这个问题。 $boards{$filenum-1} = load_file($filename);
    • 关于文件句柄的好建议。我也做了这个改变。我硬着头皮读的那本书使用了 glob,所以我一直在做同样的事情。
    • 它确实将 0 留空,但使用 $boards{$filenum-1} = load_file($filename) 意味着 $boards{'6'} 将包含“board7\.brd”的内容。如果您真的只想将板视为一个数组,请将其声明为这样,并使用 push @boards, load_file($filename) 加载它
    猜你喜欢
    • 1970-01-01
    • 2015-08-23
    • 2012-02-15
    • 2013-05-04
    • 1970-01-01
    • 2018-06-10
    • 2011-02-20
    • 2010-12-29
    相关资源
    最近更新 更多