我该如何在Perl中创建多维数组?

5
我正在创建一个多维数组,方法如下:
#!/usr/bin/perl
use warnings;
use strict;

my @a1 = (1, 2);
my @a2 = (@a1, 3);

但事实证明,我仍然得到了一个一维数组...在 Perl 中应该怎么做?

1
可能是如何在Perl中创建二维数组?的重复问题。 - Nathan Fellman
1
请仅返回翻译后的文本:同时也可以访问https://dev59.com/EnRC5IYBdhLWcg3wYP6h。 - Nathan Fellman
6个回答

10

你得到一个一维数组,因为数组@a1在括号内部被展开。所以,假设:

my @a1 = (1, 2);
my @a2 = (@a1, 3);

那么你的第二个语句等同于my @a2 = (1,2,3);

创建多维数组时,你有几个选择:

  1. 直接分配每个值
  2. 取消引用现有数组
  3. 插入一个引用

第一种选项基本上是$array[0][0] = 1;,并不是很令人兴奋。

第二个选项是这样做的:my @a2 = (\@a1, 3);。请注意,这会生成对数组@a1的命名空间的引用,因此如果您稍后更改@a1@a2中的值也会发生更改。这并不总是一个推荐的选项。

第二个选项的变体是这样做的:my @a2 = ([1,2], 3);。方括号将创建一个匿名数组,它没有命名空间,只有一个内存地址,并且只存在于@a2中。

第三个选项有点更加晦涩,是这样做的:my $a1 = [1,2]; my @a2 = ($a1, 3);。它将完全像2一样工作,只是数组引用已经在标量变量$a1中。

注意在给数组赋值时,圆括号()和方括号[]的区别。方括号[]创建一个匿名数组,返回一个数组引用作为标量值(例如可以被$a1$a2[0]所持有)。
另一方面,圆括号仅仅改变操作符的优先级,实际上并不起到任何作用。
考虑下面这段代码:
my @a2 = 1, 2, 3;
print "@a2";

这将打印1。如果你使用warnings,你也会得到一个警告,如下所示:Useless use of a constant in void context。基本上,发生了这样的情况:

my @a2 = 1;
2, 3;

因为逗号(,)的优先级低于等号=。(请参见perldoc perlop中的“运算符优先级和结合性”)。括号只是简单地否定了=,的默认优先级,并将1,2,3分组在一起成为一个列表,然后传递给@a2。所以,简而言之,方括号[]有一些神奇的功能:它们创建匿名数组。括号()只是改变优先级,就像在数学中一样。文档中有很多内容可供阅读。这里曾经有人向我展示了一个非常好的解引用链接,但我不记得是什么了。在perldoc perlreftut中,您将找到有关引用的基本教程。在perldoc perldsc中,您将找到有关数据结构的文档(感谢Oesor提醒我)。

当使用“1.直接赋值”时,例如$array[0][0] = 1;,由于 Perl 数组本质上是一维的,Perl 是否在此处创建并引用匿名数组? - Je Rog
@Je Rog:是的,$array[0][0] = 1 基本上等同于 $array[0] = [1]。它可以这样理解:"从数组的标量引用中,取出第一个元素的第一个元素,并将其设置为1",自动创建一个匿名数组来存储它。如果你使用 strict,你只需要声明 my @array - TLP

6
我建议阅读 perlreftut, perldscperllol,最好在同一天内完成,并使用Data::Dumper打印数据结构。这些教程相互补充,我认为它们一起学习效果更佳。可视化数据结构对我帮助很大,让我相信它们真的有效(严肃地),并且可以看到我的错误。

1
本质上,这是一个仅提供链接的答案。 - Peter Mortensen

4

数组包含标量,因此您需要添加一个引用。

my @a1 = (1,2);
my @a2 = (\@a1, ,3);

您需要阅读http://perldoc.perl.org/perldsc.html,这是关于Perl数据结构的文档。


@Oesor,如何对@a1进行深拷贝,以便如果@a1发生更改,@a2不会受到影响? - Je Rog
@Je Rog: my @a2 = ([@a1], 3); @Je Rog:my @a2 = ([@a1], 3); - Blagovest Buyukliev
这在某些情况下有效,但并非所有情况都适用;例如,如果@a2是对象数组。如果它是任何复杂数据结构,您应该使用Storable或Clone将其深度复制到引用中。 - Oesor
@Blagovest Buyukliev,{}代表哈希,()代表列表,那么[]是什么意思? - Je Rog
1
@Je Rog:my $array_ref= [1,2];my @array= (1,2); 的区别在于,你可以通过 $array_ref->[0]$array[0] 来访问元素。 - mirod
显示剩余2条评论

2
所有数据结构(包括多维数组)在Perl中最重要的一点是,尽管它们可能看起来不同,但Perl的@ARRAY%HASH都是内部一维的。它们只能保存标量值(表示字符串、数字或引用)。它们不能直接包含其他数组或哈希表,而是包含对其他数组或哈希表的引用
现在,由于顶层只包含引用,如果您尝试使用简单的print()函数打印出数组,您会得到一个不太好看的结果,如下所示:
    @AoA = ( [2, 3], [4, 5, 7], [0] );
    print $AoA[1][2];
    7
    print @AoA;
    ARRAY(0x83c38)ARRAY(0x8b194)ARRAY(0x8b1d0)

这是因为Perl从不(永远不会)隐式解引用您的变量。如果您想访问引用所指向的内容,则必须自己使用前缀类型指示符,例如${$blah},@{$blah},@{$blah[$i]},或者后缀指针箭头,例如$a->[3],$h->{fred},甚至$ob->method()->[3]
来源:perldoc
现在来回答您的问题。这是您的代码:
my @a1 = (1,2);
my @a2 = (@a1,3);

请注意,数组包含标量值。因此,您需要使用引用,并且可以通过在要引用的数组名称前使用\关键字来添加引用。

像这样:

my @a2 = (\@a1, ,3);

1

内部数组应该是外部数组中的标量引用:

my @a2 = (\@a1,3); # first element is a reference to a1
print ${$a2[0]}[1]; # print second element of inner array

0

这是一个关于2D数组的简单示例,作为参考:

my $AoA = undef;
for(my $i=0; $i<3; $i++) {
   for(my $j=0; $j<3; $j++) {
      $AoA->[$i]->[$j] = rand(); # Assign some value
   }
}

“as ref”是什么意思?“作为参考”?“通过引用使用”?“在互联网上的某个地方被引用,例如在这里的答案或文档中?”还是其他什么?请通过编辑您的答案来回复,而不是在评论中回复(不要包含“编辑:”,“更新:”或类似内容 - 答案应该看起来像今天写的)。 - Peter Mortensen
好的,sushant已经离开大楼,所以我们可能永远不会知道。 - Peter Mortensen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接