有关创建嵌套数组的循环问题

时间:2019-07-02 04:02:00

标签: arrays perl for-loop nested

为三个元素数组创建乘积矩阵。我知道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;
}

函数调用后的输出为:

ARRAY(0x55bbe2c667b0) 
ARRAY(0x55bbe2c667b0) 
ARRAY(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!

2 个答案:

答案 0 :(得分:4)

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

一种方式

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;

由外部@matrix形成的数组map具有每个元素的数组引用,因此(至少)是二维结构(“矩阵”)。这些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的漂亮机器上,此打印结果

         Rate direct  w_map  w_tmp
direct 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%,我也认为这是最清晰的。通过避免范围和标量,可以显式改善循环,并且可以通过使用索引来加速“直接”方法。但是这些都是可怕的微观优化,最多只能带来附带的好处。

请注意,此类计时仅对于真正大量的数据才有意义,而上述情况则没有。 (我确实对这两个尺寸进行了十倍大的测试,结果非常相似。)

答案 1 :(得分: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;
}