Perl二维数组用法全程剖析

开发 架构
Perl二维数组的概念你是否了解,这里向大家简单介绍一下Perl二维数组的概念,它相当容易理解,并且本文中出现的每个例子都有可能在实际应用中出现。

本文和大家重点讨论一下PerlPerl二维数组的概念,PerlPerl二维数组简单说就是数组的数组,创建一个数组的数组(有时也可以叫“列表的列表”,不过不太准确)真是再简单也不过了。请看下面详细介绍。

Perl二维数组

非常简短的一个Perl二维数组教程,由鄙人翻译完成。

***版本可以从这里获取(POD格式):
http://svn.perlchina.org/trunk/POD2-CN/lib/POD2/CN/perllol.pod

NAME
perllol-操作数组的数组(Perl二维数组)

说明

Perl二维数组中声明和访问数组的数组

创建一个数组的数组(有时也可以叫“列表的列表”,不过不太准确)真是再简单也不过了。它相当容易理解,并且本文中出现的每个例子都有可能在实际应用中出现。

数组的数组就是一个普通的数组(@AoA),不过可以接受两个下标("$AoA[3][2])。
下面先定义一个这样的数组:

  1. "#一个包含有“指向数组的引用”的数组  
  2. @AoA=(  
  3. ["fred","barney"],  
  4. ["george","jane","elroy"],  
  5. ["homer","marge","bart"],  
  6. );  
  7.  
  8. print$AoA[2][2];  
  9. bart  
  10.  

 

你可能已经注意到,外面的括号是圆括号,这是因为我们想要给数组赋值,所以需要圆括号。如果你*不*希望这里是@AoA,而是一个指向它的引用,那么就得这样:

  1. #一个指向“包含有数组引用的数组”的引用  
  2. $ref_to_AoA=[  
  3. ["fred","barney","pebbles","bambam","dino",],  
  4. ["homer","bart","marge","maggie",],  
  5. ["george","jane","elroy","judy",],  
  6. ];  
  7.  
  8. print$ref_to_AoA->[2][2];  
  9.  

 注意外面的括号现在变成了方括号,并且我们的访问语法也有所改变。这时因为和C不同,在Perl中你不能自由地交换数组和引用(在C中,数组和指针在很多地方可以互相代替使用)。$ref_to_AoA是一个数组引用,而@AoA是一个数组。同样地,$AoA[2]也不是一个数组,而是一个数组引用。所以下面这两行:

$AoA[2][2]
$ref_to_AoA->[2][2]

也可以用这两行来代替:

$AoA[2]->[2]
$ref_to_AoA->[2]->[2]

这是因为这里有两个相邻的括号(不管是方括号还是花括号),所以你可以随意地省略箭头符号。但是如果$ref_to_AoA后面的那个箭头不能省略,因为省略了就没法知道$ref_to_AoA到底是引用还是数组了^_^。#p#

修改Perl二维数组

前面的例子里我们创建了包含有固定数据的Perl二维数组,但是如何往其中添加新元素呢?再或者如何从零开始创建一个Perl二维数组呢?

首先,让我们试着从一个文件中读取Perl二维数组。首先我们演示如何一次性添加一行。首先我们假设有这样一个文本文件:每一行代表了Perl二维数组的行,而每一个单词代表了Perl二维数组的一个元素。下面的代码可以把它们储存到@AoA:

while(<>){
@tmp=split;
push@AoA,[@tmp }

你也可以用一个函数来一次读取一行:

for$i(1..10){
$AoA[$i]=[somefunc($i)];
}

或者也可以用一个临时变量来中转一下,这样看起来更清楚些:

for$i(1..10){
@tmp=somefunc($i);
$AoA[$i]=[@tmp];
}

注意方括号"[]"在这里非常重要。方括号实际上是数组引用的构造器。如果不用方括号而直接写,那就犯了很严重的错误:$AoA[$i]=@tmp;

你看,把一个数组赋值给了一个标量,那么其结果只是计算了@tmp数组的元素个数,我想这肯定不是你希望的。

如果你打开了"usestrict",那么你就得先定义一些变量然后才能避免警告:

 

  1. usestrict;  
  2. my(@AoA,@tmp);  
  3. while(<>){  
  4. @tmp=split;  
  5. push@AoA,[@tmp];  
  6. }  
  7.  

 

当然,你也可以不要临时变量:

while(<>){
push@AoA,[split];
}

如果你知道想要放在什么地方的话,你也可以不要push(),而是直接进行赋值: 

  1. my(@AoA,$i,$line);  
  2. for$i(0..10){  
  3. $line=<>;  
  4. $AoA[$i]=[split'',$line];  
  5. }  
  6.  

 甚至是这样: 

  1. my(@AoA,$i);  
  2. for$i(0..10){  
  3. $AoA[$i]=[split'',<>];  
  4. }  
  5.  

 你可能生怕<>在列表上下文会出差错,所以想要明确地声明要在标量上下文中对<>求值,这样可读性会更好一些:(译者注:列表上下文中,<>返回所有的行,标量上下文中<>只返回一行。) 

  1. my(@AoA,$i);  
  2. for$i(0..10){  
  3. $AoA[$i]=[split'',<>];  
  4. }  
  5.  

 如果你想用$ref_to_AoA这样的一个引用来代替数组,那你就得这么写:

while(<>){
push@$ref_to_AoA,[split];
}

现在你已经知道如何添加新行了。那么如何添加新列呢?Perl二维数组中如果你正在做数学中的矩阵运算,那么要完成类似的任务: 

  1. for$x(1..10){  
  2. for$y(1..10){  
  3. $AoA[$x][$y]=func($x,$y);  
  4. }  
  5. }  
  6.  
  7. for$x(3,7,9){  
  8. $AoA[$x][20]+=func2($x);  
  9. }  
  10.  

 想要访问的某个元素是不是存在是无关紧要的:因为如果不存在那么Perl会给你自动创建!新创建的元素的值是"undef"。

如果你想添加到一行的末尾,你可以这么做:

#添加新列到已存在的行
push@{$AoA[0]},"wilma","betty";

注意我*没有*这么写:

push$AoA[0],"wilma","betty";#错误!

事实上,上面这句根本就没法通过编译!为什么?因为push()的***个参数必须是一个真实的数组,不能是引用。#p#

访问和打印

现在是打印Perl二维数组的时候了。那么怎么打印?很简单,如果你只想打印一个元素,那么就这么来一下:

print$AoA[0][0];

如果你想打印整个数组,那你可不能这样:print@AoA;#错误!

因为你这么做只能得到一列引用,Perl从来都不会自动地为你解引用。作为替代,你必须得弄个循环或者是双重循环。用shell风格的for()语句就可以打印整个Perl二维数组:

for$aref(@AoA){
print"\t[@$aref],\n";
}

如果你要用下标来遍历的话,你得这么做:

for$i(0..$#AoA){
print"\telt$iis[@{$AoA[$i]}],\n";
}

或者这样用双重循环(注意内循环):

for$i(0..$#AoA){
for$j(0..$#{$AoA[$i]}){
print"elt$i$jis$AoA[$i][$j]\n";
}
}

如同你看到的一样,它有点儿复杂。这就是为什么有时候用临时变量能够看起来更简单一些的原因: 

  1. for$i(0..$#AoA){  
  2. $aref=$AoA[$i];  
  3. for$j(0..$#{$aref}){  
  4. print"elt$i$jis$AoA[$i][$j]\n";  
  5. }  

哦,好像还有点复杂,那么试试这样: 

  1. for$i(0..$#AoA){  
  2. $aref=$AoA[$i];  
  3. $n=@$aref-1;  
  4. for$j(0..$n){  
  5. print"elt$i$jis$AoA[$i][$j]\n";  
  6. }  
  7. }  
  8.  

 切片

切片是指Perl二维数组的一部分。如果你想要得到多维数组的一个切片,那你得进行一些下标运算。通过箭头可以方便地为单个元素解引用,但是访问切片就没有这么好的事了。当然,我们可以通过循环来取切片。

我们先演示如何用循环来获取切片。我们假设@AoA变量的值和前面一样。

@part=();
$x=4;
for($y=7;$y<13;$y++){
push@part,$AoA[$x][$y];
}

这个循环其实可以用一个切片操作来代替:
@part=@{$AoA[4]}[7..12];

不过这个看上去似乎略微有些复杂。

下面再教你Perl二维数组中如何才能得到一个*二维切片*,比如$x从4到8,$y从7到12,应该怎么写?

@newAoA=();
for($startx=$x=4;$x<=8;$x++){
for($starty=$y=7;$y<=12;$y++){
$newAoA[$x-$startx][$y-$starty]=$AoA[$x][$y];
}
}

也可以省略掉中间的那层循环:

for($x=4;$x<=8;$x++){
push@newAoA,[@{$AoA[$x]}[7..12]];
}

其实用map函数可以更加简练:

@newAoA=map{[@{$AoA[$_]}[7..12]]}4..8;

虽然你的经理也许会抱怨这种难以理解的代码可能会带来安全隐患,然而这种观点还是颇有争议的(兴许还可以更加安全也说不定^_^)。换了是我,我会把它们放进一个函数中实现:

@newAoA=splice_2D(\@AoA,4=>8,7=>12);
subsplice_2D{
my$lrr=shift;#指向Perl二维数组的引用
my($x_lo,$x_hi,
$y_lo,$y_hi)=@_;

returnmap{
[@{$lrr->[$_]}[$y_lo..$y_hi]]
}$x_lo..$x_hi;
}

【编辑推荐】

  1. Perl变量中Perl数组概念详解
  2. 深入解析Perl中Perl数组的使用
  3. Perl学习笔记 Perl双引号和单引号的区别
  4. 揭秘Perl变量中Perl纯变量用法
  5. 深入解析Perl内部函数的使用

 


 

责任编辑:佚名 来源: chinaunix.net
相关推荐

2010-07-19 13:06:13

Perl二维数组

2010-07-19 13:17:12

Perl二维数组

2009-11-16 17:07:58

PHP二维数组

2009-11-16 17:41:41

PHP二维数组

2021-01-15 08:19:26

二维数组LeetCode

2009-09-16 17:29:10

Linq查询二维数组

2009-08-07 10:12:09

C#二维数组

2010-07-19 16:25:06

Perl数组

2010-07-20 15:02:20

Perl数组

2010-07-21 13:59:59

Perl引用

2009-11-17 09:46:31

PHP二维数组赋值

2021-02-20 20:27:44

数组前缀性能

2009-12-18 15:11:05

Ruby输出二维数组

2010-03-05 14:05:02

Python二维数组

2010-07-20 13:02:08

Perl数组

2010-07-16 10:20:46

Perl关联数组

2010-07-23 14:53:21

Perl Unicod

2010-07-16 10:30:10

Perl关联数组

2009-11-25 11:14:12

PHP二维数组赋值

2009-09-18 11:33:37

C#二维数组初始化
点赞
收藏

51CTO技术栈公众号