【Perl】列表与数组
目录
列表指的是标量的有序集合,而数组则是存储列表的变量
数组
- 假如你对索引值超过数组尾端的元素进行赋值,数组将会根据需要自动扩大——只要有可用的内存分配给Perl,数组的长度是没有上限的。如果在扩展过程中需要创建增补元素,那么它们的默认取值为undef:
$rocks[0] = 'bedrock'; #一个元素
$rocks[1] = 'slate'; #又一个
$rocks[2] = 'lava'; #再来一个
$rocks[3] = 'crushed rock'; #再来一个
$rocks[99] = 'schist'; #现在有95个undef元素
- 数组的最后一个元素的索引值是$#name,这个数字比数组元素的个数少1,因为还有一个编号为0的元素:
- $rocks[$#rocks] = 'hard rock';
- $rocks[-1] = 'hard rock';
假如你在数组中有3个元素,则有效的负数索引值为-1(最后一个元素)、-2(中间的元素)、-3(第一个元素)。实践中,似乎没有人会使用-1以外的负数索引值
列表
- 列表直接量,可以由圆括号内用逗号隔开的一串数据表示,而这些数据就称为列表元素。例如:
- (1,2,3) #包含1,2,3这三个数字的列表
- (1,2,3,) #末尾的逗号会被忽略
- ("fred",4.5) #两个元素,“fred"和4.5
- ( ) #空列表,0个元素
- (1..100) #100个整数构成的列表
..范围操作符
上例最后一行用到了..范围操作符,该操作符会从左边的数字计数到右边,每次加1,以产生一连串的数字。
(1..5) #与(1,2,3,4,5)相同
(1.7..5.7) #同上,但这两个数字都会被去掉小数部分
(5..1) #空列表,..只能向上计数
(0,2..6,10,12)
($m..$n) #范围由$m和$n当前的值来决定
qw简写
("fred","barney","betty","wilma","dino");
《 == 》qw( fred barney betty wilma dino );
两种写法等价
- qw表示"quoted word(加上引号的单词)"或"quated by whitespace(用空白圈引)"
- Perl会将其当成单引号内的字符串来处理(所以,在qw构建的列表中,不能像双引号内的字符串一样使用\n或$fred)。
- 除了以一对圆括号作为界定符,Perl还允许用任何标点符号作为界定符
列表的赋值
- 就像标量值可被赋值给变量一样,列表值也可被赋值给变量:
($fred,$barney,$dino) = ("flintstone","rubble","undef");
左侧列表中的三个变量会依次被赋予右侧列表中对应的值,相当于分别做了三次独立的赋值操作。 - Perl中互换两个变量的值
- ($fred,$barney) = ($barney,$fred);
- ($betty[0],$betty[1]) = ($betty[1],$betty[0]);
@字符
- 构建一个字符串数组
($rocks[0],$rocks[1],$rocks[2],$rocks[3]) = qw/talc mica feldspar quartz/;
当你希望引用整个数组时,Perl提供了一个简单的记法。之哟啊在数组名之前加上@字符(后面没有检索用的方括号)就可以了。这种写法在赋值操作符的两边都可以使用:
@rocks = qw/ bedrock slate lava /;
@tiny = ( ); #空列表,由于空列表里没有任何元素,也就不会有undef被赋值到列表中
@giant = 1..1e5; #包含100 000个元素的列表
@stuff = (@giant,undef,@giant); #包含200 001个元素的列表
@dino = "granite";
@quarry = (@rocks,"crushed rock",@tiny,$dino);
最后一行进行的赋值运算会将@quarry设成拥有5个元素的列表(bedrocl、slate、lava、crushed rock、granite)
- 数组名会被展开成(它所拥有的)元素列表,因为数组只能包含标量,不能包含其他数组,所以数组无法成为列表中的元素
- 要留意的是:将某个数组复制到另一个数组时,仍然算是列表的赋值运算,只不过这些列表是存储在数组里而已
@copy = @quarry; #将一个数组中的列表复制到另一个数组
pop和push操作符
- pop操作符负责取出数组中最后一个元素并将其作为返回值返回
- @array = 5..9;
- $fred = pop(@array);
- $barney = pop @array;
- pop(@array);
pop后面加不加括号都可以。Perl惯例:只要不会因为拿掉括号而改变原意,括号就是可以省略的
- push操作符
- push(@array,0);
- push @array,8;
- push @array,1..10;
- push的第一个参数或者pop的唯一参数都必须是要操作的数组变量——对列表直接量进行压入(push)或弹出(pop)操作是没有意义的。
shift和unshift
unshift和shift操作符是对数组的"开头"进行相应的处理。
splice操作符
- splice:添加或移除数据中间的某些元素
- splice最多可接受4个参数,最后两个参数是可选参数
- 第1个参数是要操作的目标数组,第二个参数是要操作的一组元素的开始位置。如果仅仅给出这两项参数,Perl会把从给定位置开始一直到末尾的全部元素取出来并返回:
- @array = qw( pebbles dino fred barney betty );
- $removed = splice(@array,2);
# 在原来的数组中删除fred及其后面的元素
# @removed变成qw( fred barney betty )
# 而原先的@array则变成qw(pebbles dino)
- 第3个参数指定要操作的元素长度。通过这个参数,可以删掉数组中间的一个片段。
@array = qw( pebbles dino fred barney betty );
@removed = splice(@array,1,2);
#删除dino和fred两个元素
#@removed变成qw( dino fred );
#而@array则变成qw(pebbles barney betty);
- 第4个参数是要替换的列表。可以补充新的元素到原来的数组中,替换的列表长度不一定要和拿走的元素片段一样长。
@array = qw( pebbles dino fred barney betty );
@removed = splice @array,1,2,qw(wilma); #删除dino和fred
#@removed变成qw(dino fred);
#@array变成qw(pebble wilma barney betty);
- 实际上添加元素列表不需要预先删除某些元素,把表示长度的第三个参数设为0,即可不加删除地插入到新列表。
表示在第2个参数的位置插入新的列表元素
字符串中的数组内插
- 和标量一样,数组的内容同样可以被内插到双引号串中。内插时,会在数组的各个元素之间自动添加分隔用的空格。
@rocks = qw{ flintstone slate rubble };
print "quartz @rocks limestone\n";
- 数组被内插后,首尾都不会增添额外的空格
- 如果变量变量为邮箱格式,则该变量变量要将@转义,或直接用单引号定义邮箱字符串
foreach控制结构
foreach循环能逐项遍历列表中的值,依次迭代
foreach $rock (qw/ bedrock slate lava /){
print "One rock is $rock.\n";
}
- 每次循环迭代时,控制变量($rock)都会从列表中取得新的值。
- 控制变量并不是列表元素的复制品——实际上,它就是列表元素本身。假如在循环中修改了控制变量的值,也就同时修改了这个列表元素。
- 当循环结束后,控制变量的值仍然是循环执行之前的值,Perl会自动存储foreach循环的控制变量并在循环结束之后还原。也就是说,加入你想将循环的控制变量取名为$rock的话,不必担心之前是否用过同名的变量。
Perl最喜欢用的默认变量:$_
当未告知Perl使用哪个变量或数值时,Perl都会自动使用$_ ,从而使程序员免于命名和键入新变量的痛苦。
foreach (1..10){
print "I can count to $_!\n";
}
reverse操作符
- reverse操作符会读取列表的值(也可能来自数组),并按相反的次序返回该列表。(因此,加入你对范围操作符..只能递增计数感到失望,可以这样来弥补:
@fred = 6..10;
@barney = reverse(@fred); #得10,9,8,7,6
@wilma = reverse 6..10; #同上
@fred = reverse @fred;将逆序后的结果放回原来的那个数组
- reverse会返回次序相反的列表,但它并不会修改传进来的参数。假如返回值无处可去,那这种操作也就变得毫无意义。
sort操作符
- sort操作符会读取列表的值(也可能来自数组),而且会根据内部的字符编码顺序对它们进行排序。参数是某个输入列表,然后对它排序,继而返回排序后的列表。
@rocks = qw/ bedrocks slate rubble granite /;
@sorted = sort(@rocks); #得bedrock, granite rubble slate
@back = reverse sort @rocks; #逆序后从slate到bedrock排列
@rocks = sort @rocks;
@number = sort 97..102; #得100,101,102,97,98,99
- 从最后一个例子可以看出,将数字当成字符串来排序,这样的结果会不太对。根据默认的排序规则,任何以1开头的字符串会被排在以9开头的字符串之前。
- 和reverse一样,不会修改参数,必须将排序后的结果存回数组
each操作符
每次对数组调用each,会返回数组中下一个元素所对应的两个值——该元素的索引以及该元素的值。