4 数组和哈希(hash)表
4.1 数组和列表
如果把标量看成是Perl的单数的话,那么列表(list)和数组可以认为是Perl中的复数。列表是标量的有序集。数组是包含列表的变量。严格意义上讲,列表是指数据,而数组是其变量名。
4.1.1 数组的初始化和元素引用
列表是有序标量的集合,列表的每一个元素都是一个独立的标量,这些值是有顺序的。数组或者说列表中的元素是编了号的,其索引从整数0开始,依次递增一。
Perl中有三种变量,前面提到的标量变量的前缀($),而数组变量的前缀为(@),还有一种是哈希表的变量。
@tiny = (); #一个为空的数组。
@giant=1… 1e2 #包含从1到100,100个元素的数组
@stuff = (@giant,0,@gaint) #包含201个元素的数组
数组是通过整数编号(索引)来访问数组元素的值,而且这些整数编号是连续的,访问数组元素的语法为:
$array_name[int_index]
如:
$jerry[0]=”abc”;
$jerry[1]=”def”;
$jerry[2]=2;
下面是Perl初始化和引用的例子:
#!perl
use strict;
my @arry1=();
$arry1[0]="abc";
$arry1[1]=1;
$arry1[2]="def";
@arry1=(@arry1,"hij");
foreach my $elem(@arry1){
print("$elem, ");
#执行结果
abc, 1, def, hij,
在C语言中访问数组有越界的问题,即下标超出了数组的范围。在Perl中,在访问超出数组范围的时侯,则其值为undef。没有初始化赋值的数组元素的值也为undef。
4.1.2 特殊的数组索引
如果将一个元素存储在数组最后元素的后面位置,数组会自动增长。Perl没有长度的限制,只要你有足够的内存。
my @rocks = ();
$rocks[0]=’bedrock’ #一个元素
$rocks[1]=’slate’;又一个元素
$rocks[99]=’schist’; #数组@racks长度是100,有97个undef个元素。
有时候需要知道数组最后一个元素的索引。例如上面的rocks数组,其最后一个元素的索引为$#rocks。这和数组中元素的个数不同,因为数组的索引从0开始,所以数组racks的元素个数为$#rocks+1。这样就有了其他语言中很常见的通过索引遍历数组的for循环:
my @rocks = ();
$rocks[0]='bedrock' ;
$rocks[1]='slate';
$rocks[2]='schist';
for(my $i=0;$i<=$#rocks;$i++){
print($rocks[$i]." ");
#程序执行结果
bedrock slate schist
Larry提供了数组负数索引值的访问元素方法,如果数组有3个元素,那么有效的负数索引是-1(最后一个元素),-2(中间的元素),-3(第一个元素)。
#!perl
use strict;
my @myarr1 = ();
$myarr1[0]='bedrock' ;
$myarr1[1]='slate';
$myarr1[2]='schist';
print($myarr1[-1]." "); # schist
print($myarr1[-2]." "); # slate
print($myarr1[-3]." "); #schist
if(!defined($myarr1[-4])){ #$myarr1[-4]的值为undef
print($myarr1[-4]."undef");
#书中所说的严重错误(fatal error!)其实是指下面的初始化赋值操作
#$myarr1[-4]='aaa';
#Modification of non-creatable array value attempted, subscript -4 at p07.pl line 15.
4.1.3 数组的相关函数
Perl提供了类似于栈一样的添加或者删除数组元素的函数pop和push。Pop函数将数组的最后一个元素取出并返回:
@arr1 = 5…9; #@arr1=5,6,7,8,9
$num = pop(@arr1); #$num变量的值为9,@arr1=5,6,7,8
pop(@arr1); #@arr1 为5,6,7
如果数组为空,那么pop什么也不做,并返回undef。
@arr1 = 5...9; #@arr1=5,6,7,8,9
while(@arr1){ #为空则@rr1返回undef, boolean判断undef(0,”” 都是false)为false
print(pop(@arr1)." ");
#执行结果
9 8 7 6 5
push与pop操作正好相反,它可以将一个元素加到数组的末尾:
@arr1 = 5...9;
push(@arr1,0); #5,6,7,8,9,0
@arr2 = 10..12;
push(@arr1,@arr2); #5,6,7,8,9,0,10,11,12
Push和pop对数组的末尾进行操作,相应的,unshift和shift对一个数组的开头进行操作。下面是一些例子:
@arr1 = 5…9; #@arr1=5,6,7,8,9
$num = shift(@arr1); #$num变量的值为5@arr1= 6,7,8,9
shift(@arr1); #@arr1 为7,8,9
unshift(@arr1,6); #@arr1 => 6,7,8,9
@arr2 = (4,5);
unshift(@arr1,@arr2); #arr1 => 4,5,6,7,8,9
Perl还提供了一种不通过整数索引遍历数组的方法foreach,foreach从列表的第一个元素一直到最后一个元素,一次迭代一个,控制变量每次迭代都从列表中取出一个新值。
@arr1 = 5…9;
foreach $i(@arr1){
Print(“$i ¥n”);
4.2 哈希(hash)表
哈希表是一种重要的数据结构。哈希表也被称为"关联数组(associative arrays)"。和数组一样,哈希表可以用来存储数据,和数组不同的是,其索引不是数字,而是一个唯一的字符串(称为key)。
哈希表最大的特点是把数据的存储和查找消耗的时间大大降低,几乎可以看成是常数时间;而代价是消耗比较多的内存。目前的发展趋势来说,用空间换时间的做法是值得的。
4.2.1 Hash表的初始化和hash元素的引用
Perl中有三种类型的变量,前面提到的标量变量前缀($),数组变量(@)。而哈希hash变量的前缀为(%). 初始化赋值的一般方法如下:
my %some_hash =(
"key1"=>11.0,
"key2"=>"value2",
"key3"=>"A\n"
);
因为Perl是一种宽容的语言,下面的赋值的形式Perl也是允许的,但是推荐上一种更直观的初始化赋值的方法:
my %some_hash = (
"name", "china",
"age", 60
);
Hash表通过key来访问元素。要访问hash的元素(element),可以使用下面的语法:
这和访问数组元素的方法有些类似,但是这里下标(key)上使用的是{},而不是[]。和数组一样,访问不存在的元素或者没有值的元素返回值为undef。
$family_name{"Xiang"}="Li";
$family_name{"小眼杰伦"}="周";
Perl通过family_name前面的$和后面的{}判断其含义为hash元素,而不是标量变量什么的其他东西。所以hash表的初始化赋值也可以通过以下的方法:
C:\Users\LiXiang\Desktop\codes>more p18.pl
#!perl
use strict;
my %family_name=();
$family_name{"Xiang"}="Li";
$family_name{"小眼杰伦"}="周";
print("小眼杰伦的姓是: ".$family_name{"小眼杰伦"}."¥n");
C:\Users\LiXiang\Desktop\codes>perl p18.pl
小眼杰伦的姓是: 周
4.2.2. Hash函数
(a). keys和values函数
keys函数会返回此hash的所有keys的列表,values函数将返回所有values的列表。如果hash中没有元素,则函数将返回空列表(undef):
my %some_hash=(
"a"=>1,
"b"=>2,
"c"=>3
);
my @key=keys(%hash);
my @val=values(%hash);
foreach my $it(@keys){
print($it."\n");
[root@Ora01 codes]# perl p15.pl
有时候需要对一个哈希表是否为空用if做判断:
if(%some_hash){
#%some_hash为空时为undef,undef在判断语句中为false。
(b). each函数
如果想遍历一个哈希表中的所有元素,一种通常的方法是使用each函数,它将来返回key/value对的列表。当对同一个hash函数进行一次迭代时,将返回下一个key/value对,直到所有元素被访问则each函数将返回空表(false).
[root@Ora01 codes]# more p16.pl
#!/usr/bin/perl
use strict;
my %some_hash=(
"a"=>1,
"b"=>2,
"c"=>3
);
while((my $key, my $value)=each(%some_hash)){
print("Hash key: ".$key." Value: ".$value.".\n");
[root@Ora01 codes]# perl p16.pl
Hash key: c Value: 3.
Hash key: a Value: 1.
Hash key: b Value: 2.
另一种遍历哈希表的办法是通过keys函数获取所有元素的keys列表,然后通过foreach和keys列表来访问values达到遍历的目的,上例的一个等效写法:
[root@Ora01 codes]# more p17.pl
#!/usr/bin/perl
use strict;
my %some_hash=(
"a"=>1,
"b"=>2,
"c"=>3
);
foreach my $key(keys(%some_hash)){
print("Hash key: ".$key." Value: ".$some_hash{$key}."\n");
[root@Ora01 codes]# perl p17.pl
Hash key: c Value: 3
Hash key: a Value: 1
Hash key: b Value: 2
[root@Ora01 codes]#
(c). exists函数
要查看哈希表中是否存在某个key,可以通过使用exists函数,如果hash中存在此key,则返回true。
#!perl
use strict;
my %some_hash=(
"a"=>1,
"b"=>2,
"c"=>3
);
my $b_key = "b";
if(exists($some_hash{$b_key})){
print("hash \%some_hash exists key $b_key, and value :".$some_hash{"b"}."\n");
#执行运行结果
hash %some_hash exists key b, and value :2
(d). delete函数
delete函数将摸个给定的key的元素从hash中删除,如果不存在这个key则什么都不做;不会有警告或者错误信息。
#!perl
use strict;
my %some_hash=(
"a"=>1,
"b"=>2,
"c"=>3
);
delete($some_hash{"b"});
foreach my $key(keys(%some_hash)){
print("Hash key: ".$key." Value: ".$some_hash{$key}."\n");
#执行结果
Hash key: c Value: 3
Hash key: a Value: 1