列表切片
在一个列表中,特别是由函数返回的列表中,有时往往只需要取出其中的某几个元素使用。比较一般的办法是将此列表存入一个数组中,然后通过索引值来取出数组元素。但这样的做法会引入一个新的数组,且除了取用的元素以外,其他的元素都没有用处,从而造成了资源上的浪费。
Perl可以将一个列表直接当作一个数组使用,可以使用下标表达式来取出其中的一个或多个元素,这样的操作就称为列表切片。由于列表可以直接被当作数组使用,这样就避免了引入新数组的浪费。例:
$_=(1..10)[1]; #把(1..10)当作一个数组,后接下标[1]表示取用索引值为1的列表元素,并赋值给变量
在使用列表切片时,必须要在函数返回的列表的外层加上一对小括号,构造出列表上下文中的一个列表。例:
$_=(reverse 1..10)[1]; #在reverse返回的列表的外层加上一对括号,构造出列表上下文,然后再对此列表使用列表切片
切片不仅能只切出一个元素,其也可以一次性切出多个元素,并返回一个列表。如果要一次切出多个列表元素,将方括号内的单个下标数字换为由多个下标数字组成的列表即可,这个列表的小括号可以省略。数字之间顺序不限,并且可以重复。例:
($n,$m)=(1..10)[1,-1]; #切出列表中索引值为1的元素和最后一个元素,并将切出的列表赋值给变量列表
@n=(reverse 1..10)[1,1,1,1,1]; #切出5个列表中索引值为1的元素,并将切出的列表赋值给@n
注意:列表切片同列表一样,不能进行双引号内插。
数组切片
下标表达式可以用来取出数组中的一个元素,这是一种常用的可以访问单个数组元素的做法。而类似于列表切片,在数组中也可以一次性切出多个数组元素,并返回一个列表。这样的操作就称为数组切片。数组切片是另一种访问数组元素的做法,其可以一次性访问多个数组元素。
Perl中,$符号一般指取用单个元素,而@符号不仅可以表示整个数组,其也可以与$相对,表示取用多个元素,@是下标表达式的第二种标识符。所以如果下标表达式使用@开头,就表示取用多个数组元素,即数组切片。而相对应的,其下标数字也应由一个数字变为由多个索引值构成的列表。数组切片的返回值也是一个列表,下标数字顺序不限,且可以重复,这些都与列表切片一致。例:
$n[1] #使用$作为下标表达式的标识符,取出数组中的一个元素
@n[1..5] #使用@作为下标表达式的标识符,取出数组中的多个元素
数组切片返回的是一个列表,所以可以应用在各种需要列表的环境中。例:
($n,$m)=@n[2,4]; #将数组切片返回的列表赋值给变量列表
for(@n[1..5]){print} #将数组切片返回的列表作为foreach的参数
数组切片同数组一样,也可以进行双引号内插,且内插的各个数组元素之间会自动以空格隔开,这是其与列表切片的一大不同之处。例:
print"@n[1..5]"; #数组切片内插
哈希切片
哈希切片与数组切片十分相似。其使用@而不是$作为标识符,表示取用多个元素,哈希切片会返回哈希值列表。在哈希切片的下标表达式中,原先花括号围住的单个哈希键应换成由多个哈希键构成的键列表。例:
$hash{a} #取出单个哈希值
@hash{qw/a b c/} #取出qw/a b c/这个哈希键列表对应的多个哈希值,即哈希切片
通过哈希切片切出的哈希值列表可以运用于各种列表上下文中。例:
@hash{qw/a b c/}=qw/aaa bbb ccc/; #使用哈希切片同时对这三个哈希键进行赋值
同数组切片,哈希切片也可以进行双引号内插。例:
print"@hash{qw/a b c/}"; #哈希切片内插
下标表达式的特征性符号
通过上文可知,下标表达式不仅可以用来取用单个数组元素或哈希元素,其也可以用来进行上文所述的三类切片操作。而下标表达式在进行这两种不同的操作时,其返回值所处的上下文是不同的。当取用单个元素时,下标表达式返回的是一个标量,此时其上下文就是标量上下文,而进行切片操作时,下标表达式返回的是一个列表,此时其上下文则是列表上下文。而这其中的决定性因素就在于下标表达式的标识符,这是下标表达式的一类特征性符号。
下标表达式的标识符有两种:$和@,这两种符号决定了下标表达式的上下文。$符号表示取单个元素,所以当以$作为标识符时,下标表达式就是标量上下文,而@符号表示取多个元素,即切片,所以当以@作为标识符时,其上下文就是列表上下文。例:
$n[1] #由$决定标量上下文
@n[1,2] #由@决定列表上下文
列表切片是一种特殊的下标表达式,其恒为列表上下文,也就是说,即使列表切片切出的元素只有一个,此时也是列表上下文。例:
(1..5)[1] #列表切片中的下标表达式,此时为列表上下文
除了$与@,在下标表达式中还有另一类特征性符号,即方括号与花括号,这一对符号决定了下标表达式的操作对象。方括号与花括号均出现于下标表达式的下标中,用于包裹下标数字或哈希键。显然,如果下标表达式使用的是一对方括号,那么其操作对象就是一个数组或列表,而如果下标表达式使用的是一对花括号,那么其操作对象就是哈希。例:
$n[1] #由“[ ]”决定了下标表达式的操作对象是数组
@hash{qw/a b c/} #由“{ }”决定了下标表达式的操作对象是哈希
grep操作符初步
grep与下文中的map操作符都是Perl中的两个非常重要的列表操作符。grep操作符可以用来筛选一个列表中的特定元素,在列表上下文中,其可以将满足条件的所有元素作为一个列表返回,而在标量上下文中,其可以返回筛选出的列表中的元素个数,即满足条件的元素个数。
grep操作符的参数分为两部分,第一部分为一个返回布尔值的代码块,又称选择器。第二部分为需要进行筛选的数组或列表。在grep运行过程中,类似于foreach循环,$_会依次成为列表中每一个元素的临时别名,然后在代码块中对$_进行运算并得到一个布尔值,如果此布尔值为真,那么这个元素就会被筛选出来。全部筛选完毕后,grep会将所有筛选出的元素以一个列表返回。
注意,由于$_是列表元素的临时别名,所以不建议在grep的代码块中对$_的值进行修改,因为这将直接修改列表中元素的值。例:
print grep{$_>5}1..10; #$_会依次成为(1..10)中每一个元素的临时别名,并判断$_>5是否为真,如果为真则筛出。grep在列表上下文中最终返回所有符合条件的元素构成的列表
$n=grep{$_>5}1..10; #在标量上下文中返回满足条件的元素的个数
grep还有更简便的一种写法,如果代码块中的运算式简短到只有一行(如上例),就可以直接将这个运算式作为grep的第一参数书写,从而省去代码块结构,而grep的操作对象则作为其第二参数。例:
print grep$_>1,0,1,2,3; #直接将代码块改为grep的第一参数书写,第二参数为一个省略括号的列表,即grep进行筛选的列表
map操作符初步
map操作符可以用于修改列表中每一个元素的值。其工作方式和书写规则均与grep十分相似。$_会依次成为列表中每一个元素的临时别名,然后执行含有$_的代码块,从而对$_进行修改,并最终返回整个修改过的列表。
map操作符的参数同grep一样,由代码块和需要处理的数组或列表组成。且如果代码块简短到只有一行,就可以直接将代码块改写为map的第一参数。例:
print map$_+=1,1..10; #以$_分别作为列表中每一个元素的临时别名,并返回$_+=1的结果,最终输出由每一个结果所组成的列表
任何形式的grep和map语句都可以改写为foreach循环语句,但由于foreach语句每次只能返回一个元素的判断或运算结果,所以当处理整个数组或列表时,就一定需要一个临时数组来存放结果,这就造成了资源上的浪费。而grep和map可以一次性进行每个元素的运算,直接返回最终的结果列表,从而省去了创建临时数组来存放结果的麻烦,使运算更为高效,也使代码更为简洁。
樱雨楼
完成于2016.1.8
最后修改于2016.1.29