perl 数组引用_Perl中数组引用的魔力

perl 数组引用

在编程世界中,如果不遇到嵌套的数据结构,您将走得很远。 例如,JavaScript对象可能如下所示:

var cats = {
"name":"Mr. Tickles",
"owners": {
"owner1" : "Tom",
"owner2" : "Janet"
},
"color":"orange
};

在此示例中,我们在较大的cats对象内嵌套了多个所有者对象。 我们也可以对数组使用类似的东西:

var array1 = [["one", "two"], ["three", "seven", "five"]];

在这里,我们有一个嵌套数组或一个数组数组。

在JavaScript中,您可以使用点表示法或方括号表示法访问嵌套对象。 对于数组,您可以调用array1[0]并且此调用的预期输出将是该数组中的第一个数组,即[“one”, “two”]

这是我们在Perl中访问数据的方式的主要区别。 尽管两种语言的语法都非常相似,但是在Perl中访问嵌套数据可能会有些困难。 例如,如果上面有相同的嵌套数组,并且保存数组数组的变量是@array1 ,并且我们想访问$ array1中的第一个数组,并使用调用@array1[0],实际获得的输出将是第一个元素“one”.

其原因是因为Perl展平了所有嵌套数据。 如果您的数组包含多个数组,则Perl会将其解释为单个数组,并将所有数组数据混搭在一起。 Perl还以非常相似的方式解释对象或哈希。

输入数组引用

如果您不打算在访问数据时将所有数据弄平,那么最好的解决方案是在定义数组变量时使用数组引用。 这是在创建数组时完成的,远远早于我们打算访问该数组的时间。 如果数据没有存储为参考,我们将无法访问它作为参考。

在上面的示例中,我们可以按如下方式定义它:

my @array1 = ();

在这里,我们只是创建一个空数组来保存嵌套数组。 接下来,我们可以将新数组推入数组容器。

my @nestedArray = ("one", "two");
my @nestedArray2 = ("five", "seven", "three");

在这一点上,我们可能会尝试使用以下内容:

push @array1, @nestedArray;

这将完全实现我们以前的扁平数组。 相反,在将数组推入容器数组之前,我们将创建该数组的引用。

创建参考:

my $nestedArray = \@nestedArray;

这将创建一个包含嵌套数组引用的标量变量。 该引用实际上是使用反斜杠符号创建的。

现在,我们可以复制上面的代码,将引用推入数组:

push @array1, $nestedArray;

解引用引用的数组:

使用相同的格式,我们可以将尽可能多的嵌套数组推入数组容器。 稍后,我们可能要访问这些引用。 首先,让我们想象一下嵌套数据如下所示:

@array1 = [[1, 2, 4], [3, 4, 5], [8, 8, 9], [6, 7, 6]];

在这里,我们在一个数组容器内嵌套了四个数组,每个嵌套的数组包含3个整数。 让我们尝试访问最后一个嵌套数组中的第一个整数。

首先,访问引用数组的语法有些棘手。 首先,我将代码放在此处,然后解释其工作方式:

@{ $array1[3] }[0];

大括号前面的@符号告诉Perl我们正在访问数组,而array变量前面的$(标量)符号使我们只能访问容器中的单个数组。 [3]让我们访问数组的第四个元素,该元素位于索引[3]处。 这使我们获得了系列中的最后一个数组,然后在该块的结尾,我们有了熟悉的[0],它告诉Perl我们想要该数组中的第一个元素。 我们的预期回报为6。

现在,让我们看一个更复杂的问题,在这个问题中,我们必须在循环内使用许多引用。 这是称为最大路径总和的问题。 取以下数字三角形:

3,
7、4
2 4 6
8、5、9、3

这里的对象是从顶部到底部,并找到最大的求和路径,仅向右移动或向左移动。 例如,在第二行中,如果我们选择7,则无法访问6。在此示例中,最大总和路径为3、7、4、9,总和为23。

了解了解决方案后,让我们使用Perl和数组引用来解决该问题。 首先要记住的是,对于较大的三角形,将无法使用蛮力(尝试数字的每种组合)来解决此问题。 解决此类问题的最佳方法实际上是向后工作。 我们将从第3行开始,例如,并针对当前数字下两个可能数字的总和测试每个数字。 第一个数字为2,我们可能的组合为8和5。这里最大的和为10(8 + 2)。 在对每个数字进行此过程之后,我们只需删除最后一行,而仅用最高的总和替换第三行。 我们的新三角形如下所示:

3,
7、4
10、13、15

现在,我们将在第二行中执行相同的操作,这将给我们:

3,
20、19

然后是最后一行,这将给我们23。

从编程的角度考虑这个过程,而不是三角形,我们的数据输入可能是单个数组:

my @triangle = (3,7,4,2,4,6,8,5,9,3);

从这里开始,我们的过程可能是将其分成几行。 这就是嵌套引用数组起作用的地方。 我们最终想要得到的是这样的:

my @triangle = ([3],[7,4],[2,4,6],[8,5,9,3]);

最简单的方法是遍历数组,为每个嵌套数组创建引用,然后将其推入新数组。

这是我们可以做到的一种方法:

my @choppedTriangle = []; 
my @chopped = (); #Our new array container
my $start = 0;
my $stop = 0;
my $length = 1;
my $row = 1;
my $triangle = @triangle ;
while ( @choppedTriangle < @triangle ) {
my @row = ();
for (my $i=$start; $i <= $stop; $i++) {
push @choppedTriangle , $triangle[$i];
push @row , $triangle[$i];
};
my $row = \ @row ;
push @chopped , $row;
$start = $stop + 1;
$length = $length + 1;
$stop = $stop + $length;
};

在这里,我们在while循环中使用for循环。 在循环中,在每次迭代时,我们都将每个@row推入@choppedTriangle中。 这不是数组引用,而是有目的的。 在这种情况下,我们应该只具有4个嵌套数组,并且我们不希望推送超过4个嵌套数组。 @triangle也有4个嵌套数组,因此我们的while循环条件语句将在两个数组彼此相等时立即停止。 将所有行都推入@choppedtriangle后,我们想结束循环。

这项工作将全部在我们的for循环中完成。 在for循环之外,但仍在while循环中,我们将为每行创建一个数组引用,您可以在行中看到以下内容:

my $row = \@row;
push @chopped , $row;

然后,将该引用推入@chopped数组中。 我只将@choppedtriangle用作while循环的条件,一旦循环完成,就不再需要使用它了。 但是,我需要的所有嵌套数组都包含在@chopped中。

我还在循环中使用$ start,$ stop和$ length变量,使用这些变量作为索引来确定每一行的开始和结束。 例如,两者都从0开始,这将是[$ start]的索引。 由于我们要提取的第一个元素在索引0处,因此这是完美的。 在每个循环之后,我们将调整变量$ start和$ stop,以使Perl知道新行的长度。 新行将从第一行结束处开始,因此:

$start = $stop + 1;

然后,长度也将是$length = $length + 1 ,因为我们从第1行开始,并且随后的每一行都长一个字符。 然后,无论新长度是多少,我们都将使用该值来设置新的$stop变量,该变量将在长度之后仅一个字符,从而使我们能够获得介于新的$start$stop变量之间的所有内容。

有了这一点,我们现在应该有了一个包含4个嵌套数组的数组。 我们接下来要做的是遍历数组,然后遍历每个嵌套数组。 我们将要做前面提到的相同的事情,将当前行与其下一行进行比较,并用最大的和替换这些值。 我的想法是这样。 假设我们当前的行是这样的:

[2,4],而其下一行是[1,2,3]。

我将创建一个临时数组,并在第一行进行迭代。 由于数组的长度仅为2,因此此循环将仅包含2次迭代。在每次迭代中,我将进行2个比较:2 + 1和2 + 2,然后是4 + 2和4 + 3。 在每次迭代中,我将采用最大的比较和,并将其推入临时数组。 因此,我的临时数组现在将保存值[4,7]。

接下来,我将[2,4]的上一行替换为新的临时数组[4,7]。

最后,我将重置正在处理的行,新行将成为三角形的下一行,并且将重置我正在比较的行,这将是我们刚设置的行,[4, 7]。

让我在这里放入将要使用的代码,然后说明如何实现它:

首先,我将创建两个变量来控制要迭代的行:

my $iter = 1;
my $iter2 = 2;

我的想法是,在每个循环的末尾更改这些变量,这将允许我移至下一行。

my @tempArray = ();
my $chopRows = @chopped -1;
for (my $i=0; $i < $chopRows; $i++) {
@tempArray = ();
for (my $i=0; $i < @{ $chopped[scalar @chopped -$iter2] }; $i++) {
if(@{ $chopped[scalar @chopped -$iter2] }[$i] + @{ $chopped[scalar @chopped -$iter] }[$i] > @{ $chopped[scalar @chopped -$iter2] }[$i] + @{ $chopped[scalar @chopped -$iter] }[$i+1])
{
push @tempArray , @{ $chopped[scalar @chopped -$iter2] }[$i] + @{ $chopped[scalar @chopped -$iter] }[$i];
}
else
{push @tempArray ,@{ $chopped[scalar @chopped -$iter2] }[$i] + @{ $chopped[scalar @chopped -$iter] }[$i+1];
};
};
@{ $chopped[scalar @chopped -$iter2] } = @tempArray ;
$iter = $iter + 1;
$iter2 = $iter2 + 1;
};

第一部分可能看起来很奇怪:

my @tempArray = ();
my $chopRows = @chopped -1;
for (my $i=0; $i < $chopRows; $i++) {
@tempArray = ();

由于我正在创建临时数组,然后在for循环内再次调用它。 原因是,当for循环结束时,我应该在其中包含表示总和的新值。 一旦回到循环的开始,就需要清空临时数组。 由于我是在循环外创建数组的,因此,如果我没有在每个循环的开始处将其内容清空,那么在第4次迭代(三角形的第4行)中,我们将获得一个数组,其中包含所有和的总和三角形…当我们想要的只是当前行时。 现在,在第二个循环中,我们有:

for (my $i=0; $i < @{ $chopped[scalar @chopped -$iter2] }; $i++) {

现在,这只是一个非常基本的for循环,中间有一个花哨的长度控制。 @{ $chopped[scalar @chopped -$iter2] };

希望这看起来很熟悉,因为这正是我们之前用来取消引用数组并访问其内容的方式:

@{ $array1[3] }[0];

[scalar @chopped -$iter2]此处, $iter2变量当前为2,它指向倒数第二行,基本上从@chopped数组的末尾开始工作,并向后@chopped两个位置。 这意味着,我们将遍历倒数第二行中的数字,并将其与最后一行进行比较。 完成后,我们可以将$iter2更改$iter2 3,或者简单地将$iter2 = $iter2 + 1 。 这将允许我们从末尾访问第三行,然后我们可以继续重复此过程。

为简单起见,在for循环中只有一个条件语句。 这会将当前整数与其下的两个可能整数进行比较。

if(@{ $chopped[scalar @chopped -$iter2] }[$i] + @{ $chopped[scalar @chopped -$iter] }[$i] > @{ $chopped[scalar @chopped -$iter2] }[$i] + @{ $chopped[scalar @chopped -$iter] }[$i+1])

在这里,我们正在访问解引用数组@{ $chopped[scalar @chopped -$iter2] }[$i] 。 这表示上一行的当前迭代,我们正在查看它与@{ $chopped[scalar @chopped -$iter] }[$i]的总和是否大于@{ $chopped[scalar @chopped -$iter2] }[$i] + @{ $chopped[scalar @chopped -$iter] }[$i+1]) 。 在这里,我们同时使用了变量$ iter2和$ iter,为我们提供了每一行的值,$ iter是最后一行,$ iter2是上面一行。

如果此条件返回true,则推入当前值:

 @tempArray , @{ $chopped[scalar @chopped -$iter2] }[$i] + @{ $chopped[scalar @chopped -$iter] }[$i];

否则,我们推其他价值。 这样,我们不需要比较值是否相等。 因为如果第一个值不大,则无论如何我们都会推入另一个值,因为它们是否相同并不重要。

最后,在循环结束时,我们重置当前行的值,将其替换为temparray的值,还重置$ iter和$ iter2变量的值:

@{ $chopped[scalar @chopped -$iter2] } = @tempArray ;
$iter = $iter + 1;
$iter2 = $iter2 + 1;

这使我们回到循环的顶部,在此我们重置@temparray值,并从下一行开始。 现在,我们可以打印@tempArray的值,该值将保留最终值。

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

要一起查看整个代码块,这是我所拥有的:

#!/usr/bin/perl
use strict;
use warnings;
# By starting at the top of the triangle below and moving to adjacent numbers on the row below, the maximum total from top to bottom is 23.
# 3,
# 7, 4
# 2, 4, 6
# 8, 5, 9, 3
# 23!
# starting triangle array
my @triangle = (3,7,4,2,4,6,8,5,9,3);
# array to hold
my @choppedTriangle = [];
my @chopped = ();
my $start = 0;
my $stop = 0;
my $length = 1;
my $row = 1;
my $triangle = @triangle ;
while ( @choppedTriangle < @triangle ) {
my @row = ();
for (my $i=$start; $i <= $stop; $i++) {
push @choppedTriangle , $triangle[$i];
push @row , $triangle[$i];
};
my $row = \ @row ;
push @chopped , $row;
$start = $stop + 1;
$length = $length + 1;
$stop = $stop + $length;
};
my $iter = 1;
my $iter2 = 2;
my @tempArray = ();
my $chopRows = @chopped -1;
for (my $i=0; $i < $chopRows; $i++) {
@tempArray = ();
for (my $i=0; $i < @{ $chopped[scalar @chopped -$iter2] }; $i++) {
if(@{ $chopped[scalar @chopped -$iter2] }[$i] + @{ $chopped[scalar @chopped -$iter] }[$i] > @{ $chopped[scalar @chopped -$iter2] }[$i] + @{ $chopped[scalar @chopped -$iter] }[$i+1])
{
push @tempArray , @{ $chopped[scalar @chopped -$iter2] }[$i] + @{ $chopped[scalar @chopped -$iter] }[$i];
}
else
{push @tempArray ,@{ $chopped[scalar @chopped -$iter2] }[$i] + @{ $chopped[scalar @chopped -$iter] }[$i+1];
};
};
@{ $chopped[scalar @chopped -$iter2] } = @tempArray ;
$iter = $iter + 1;
$iter2 = $iter2 + 1;
};
foreach my $x ( @tempArray ) {
print "$x \n";
}

这可能有点麻烦,但是我发现当习惯于在Perl中引用和取消引用嵌套数据时,诸如此类的复杂情况可以帮助我理解正在发生的事情以及它如何如此有用。 让我知道您是否有任何反馈!

翻译自: https://hackernoon.com/the-magic-of-array-references-in-perl-cb0bdd82a448

perl 数组引用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值