Perl学习笔记5——高级Perl技巧:切片、grep与map初步

列表切片

在一个列表中,特别是由函数返回的列表中,有时往往只需要取出其中的某几个元素使用。比较一般的办法是将此列表存入一个数组中,然后通过索引值来取出数组元素。但这样的做法会引入一个新的数组,且除了取用的元素以外,其他的元素都没有用处,从而造成了资源上的浪费。

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

    原文作者:樱雨楼
    原文地址: https://www.jianshu.com/p/d3727f9f93b4
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞