【问题标题】:For Loop Issues in creating nested array创建嵌套数组时的 For 循环问题
【发布时间】:2019-11-12 16:03:47
【问题描述】:

为三个元素数组创建一个产品矩阵。我知道 Perl 没有多维数组并且是扁平的。我一直在使用 refs,但我似乎无法解决 for 循环问题,将三个产品放入一个数组并将该数组推入另一个数组。我也可能会走得很远。很好,但我在这上面花了太多时间。

我已经将值移入和移出各个位置,即 { },打印出变量直到我变蓝并使用 $last 进行调试。我可能在这一点上被炒了。

use strict;
use warnings;

my @array1 = (1, 2, 3);
my @array2 = (2, 4, 6);
my @matrixArray = ();
my $matrixArray;
my @row; 

my @finalArray = maths(\@array1, \@array2);
print @finalArray;

sub maths{
    my $array1ref = shift;
    my $array2ref = shift;
    my $value1;
    my $value2;
    my $maths;
    my @row = ();

    my @array1 = @{$array1ref};
    my @array2 = @{$array2ref};
    my $len1 = @array1;
    my $len2 = @array2;

for my $x (0 ..($len1 -1)){
    #iterate through first array at each value
    $value1 = $array1[$x];
        #print $value1, " value1 \n";

    for my $y (0 .. ($len2 -1)){
    #iterate through second array at each value
    $value2 = $array2[$y];
            #print $value2, " value2 \n";

    #calculate new values
    $maths = $value1 * $value2;
            #exactly right here
            #print $maths, " maths \n" ;
            push @row, $maths;
    }
}
#and exactly right here but not set of arrays
#print @row, "\n";
return @row;       
}

目前我可以得到这个:246481261218。这是正确的愚蠢数学但是......

它应该显示为一个矩阵:

2 4 6 4 8 12 6 12 18

我没有传递三个数组,所以我的问题似乎出在子例程中,然后我才能继续处理其他任何事情。这似乎是我经常怀念的一个主题。很抱歉,如果我听起来无能。

编辑*** 这是有效的,但我无法打开它

use strict;
use warnings;

my @array1 = (1, 2, 3);
my @array2 = (2, 4, 6);
my @matrixArray = ();

maths(\@array1, \@array2);
foreach my $x (@matrixArray){
    print "$x \n";
}

sub maths{
    my $array1ref = shift;
    my $array2ref = shift;
    my $value1;
    my $value2;
    my $maths;
    my @row = ();
    my $row; 

    my @array1 = @{$array1ref};
    my @array2 = @{$array2ref};
    my $len1 = @array1;
    my $len2 = @array2;

    for my $x (0 ..($len1 -1)){
        #iterate through first array at each value
        $value1 = $array1[$x];

        for my $y (0 .. ($len2 -1)){
        #iterate through second array at each value
        $value2 = $array2[$y];

        #calculate new values
        $maths = $value1 * $value2;
        push @row, $maths;
        $row  = \@row;
    }
        push @matrixArray, $row;
    }
    return @matrixArray;
}

函数调用后的输出是这样的:

数组(0x55bbe2c667b0) 数组(0x55bbe2c667b0) 数组(0x55bbe2c667b0)

这将是 $x 的(第 10 行)打印。

****编辑 这工作(几乎):

print join(" ", @{$_}), "\n" for @matrixArray;

输出有点不对……

2 4 6 4 8 12 6 12 18

2 4 6 4 8 12 6 12 18

2 4 6 4 8 12 6 12 18

值得注意的是:我知道 $x 是一个数组,但我似乎在尝试正确解压缩它时遇到了麻烦。而且我不再是 Perl 的粉丝了。我渴望 Python 的峡湾。

和 ***** 编辑 这很好用,我从中得到了三个数组:

sub maths{
my ($array1, $array2) = @_;
my @res;
for my $x (@$array1) {
    my @row;
    for my $y (@$array2) {
        push @row, $x * $y;
    }

    push @res, \@row;
}
    #This is the correct structure on print @res!
    return @res;
}

但是,虽然它正确地组合在一起,但调用后我没有输出

maths(\@array1, \@array2);

这里什么都没有……

print @res;
print join(" ", @{$_}), "\n" for @res;

foreach my $x (@res){
    print join(" ", @{$x}), "\n";
}

当然还有一百万谢谢!我后悔上了这门愚蠢的课程,并担心我的成绩最终会影响我。仍然渴望 Python!

【问题讨论】:

  • 我已经格式化了你的矩阵,请检查它们是否正确。
  • 是的,更好看
  • 检查my @row = () 在我的答案中出现的位置。它需要在 x 循环内 - 每次迭代都需要一个单独的变量
  • 您最近对maths 的实现返回了一个数组,但您没有保存它(例如my @matrixArray = maths(\@array1, \@array2);)。您之前的实现将全局变量更新为副作用(这可能最好避免)。
  • 天哪!非常感谢!

标签: arrays perl for-loop nested


【解决方案1】:

看来您需要一个矩阵,其行是通过将一个数组与另一个数组的元素相乘而获得的。

一种方式

use warnings;
use strict;    
use Data::Dump qw(dd);

my @ary     = (2, 4, 6);
my @factors = (1, 2, 3);

my @matrix = map {
    my $factor = $_;
    [ map { $_ * $factor } @ary ]
} @factors;

dd @matrix;

由外部map 形成的数组@matrix 对每个元素都有数组引用,因此(至少)是一个二维结构(一个“矩阵”)。这些arrayrefs 是用[ ] 构建的,它从内部的列表中创建了一个匿名数组。该列表由map@ary 上生成。

我使用Data::Dump 很好地打印复杂数据。在核心有Data::Dumper


这样的工作量很大,而且数据量很大,效率可能很重要。普遍的看法是直接迭代应该比map 快一点,但这里有一个基准。这也有助于展示更基本的方式。

use warnings;
use strict;
use feature 'say';

use Benchmark qw(cmpthese);    

my $runfor = shift // 5;  # run each case for these many seconds

sub outer_map {
    my ($ary, $fact) = @_; 
    my @matrix = map {
        my $factor = $_; 
        [ map { $_ * $factor } @$ary ]
    } @$fact;
    return \@matrix;
}

sub outer {
    my ($ary, $fact) = @_; 
    my @matrix; 
    foreach my $factor (@$fact) {
        push @matrix, []; 
        foreach my $elem (@$ary) {
            push @{$matrix[-1]}, $elem * $factor;
        }
    }   
    return \@matrix;
}

sub outer_tmp {
    my ($ary, $fact) = @_;
    my @matrix;
    foreach my $factor (@$fact) {
        my @tmp;
        foreach my $elem (@$ary) {
            push @tmp, $elem * $factor;
        }
        push @matrix, \@tmp;
    }
    return \@matrix;
}

my @a1 = map { 2*$_ } 1..1_000;  # worth comparing only for large data
my @f1 = 1..1_000;

cmpthese( -$runfor, {
    direct => sub { my $r1 = outer(\@a1, \@f1) },
    w_tmp  => sub { my $r2 = outer_tmp(\@a1, \@f1) },
    w_map  => sub { my $r3 = outer_map(\@a1, \@f1) },
});

在带有 v5.16 的漂亮机器上打印

直接评价 w_map w_tmp 直接 11.0/s -- -3% -20% w_map 11.4/s 3% -- -17% w_tmp 13.8/s 25% 21% --

v5.29.2 和旧笔记本电脑上的结果非常相似。

所以map 比直接构建矩阵要快一点,比使用行临时数组的方法慢 15-20%,我也认为这是最清晰的。通过避免范围和标量可以稍微改进显式循环,并且可以通过使用索引来加快“直接”方法的速度。但这些都是可怕的微优化,充其量只是为了附带利益。

请注意,只有在真正大量数据的情况下,诸如此类的时间安排才有意义,而上述情况则不然。 (我确实对两个维度进行了十倍大的测试,结果非常相似。)

【讨论】:

  • dd \@matrix; ?
  • @jhnc 一个习惯,因为大多数打印机都会参考。更改为数组,因为文档确实有一个明确的示例...谢谢
  • 不,我的意思是matrix v factors
【解决方案2】:

第二个程序基本正确。

问题是你没有解压数组的第二层。

foreach my $x (@matrixArray){
    print "$x \n";
}

应该是这样的:

foreach my $x (@matrixArray) {
    print join(" ", @{$x}), "\n";
}

# or just:
print join(" ", @{$_}), "\n" for @matrixArray;

您的maths 函数可以通过删除不必要的临时变量和索引来缩短而不丢失易读性(它实际上可能使其更易读)。例如:

sub maths {
    my @array1 = @{ $_[0] };
    my @array2 = @{ $_[1] }; # or: ... = @{ (shift) };
    my @res = ();
    for my $x (@array1) {
        my @row = (); # <-- bugfix of original code
        for my $y (@array2) {
            my $maths = $x * $y;
            push @row, $maths;
        }
        push @res, \@row;
    }
    return @res;
}

【讨论】:

  • 我喜欢更简单的代码。我特别喜欢数学子。但是有一个问题,我们*需要将引用传递给函数。我不确定这是否会这样工作..
  • 它是一个替代品。 @_ 是参数数组。 $_[0] 是第一个元素。 @{ $_[0] } 将 ref 转换为列表。
  • 更简单的代码仍然会产生不必要的数组副本,并且仍然愚蠢地使用my @a = ();Better version.
  • 谢谢@ikegami,你确定副本吗?我看不出 -MO=Concise 输出有任何区别(但这确实超出了我的水平)。声明假设(显式初始化)似乎是风格选择。为什么说它“愚蠢”?
  • Re“你为什么说它“愚蠢”?”,给阅读器/维护者增加不必要的成本是一种糟糕的编程习惯的定义。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多