• Perl学习笔记03——列表和数组


    列表和数组

    1.列表指的是标量的有序集合,而数组则是存储列表的变量。更精确地说,列表指的是数据,而数组指的是变量。

    2.数组或列表中的每个元素都有相应的整数作为索引,从0开始递增,每次加1

    3.数组或列表每个元素都是独立不相关的标量值,所以列表或数组可能包含数字、字符串、undef值或是不同类型标量值的混合。

    4.列表的值不一定要放在数组里,但每个数组变量都一定包含一个列表(即便是不含任何元素的空列表)。

    访问数组中的元素

    访问数组元素:

    print $fred[0];

    修改数组元素:

    $fred[2] = "diddly";

    任何求值能得到数字的表达式都可以用作下标,假如它不是整数,则会自动舍去小数,无论正负。

    $number = 2.71828;
    print $fred[$number - 1];  #结果和print $fred[1]相同

    假如下标超出数组的末端,则对应的值将会是undef

    特殊的数组索引($#rocks

    如果对索引值超过数组尾端的元素进行赋值,数组将会根据需求自动扩大,增补元素默认取值为undef

    $rocks[0] = 'bedrock';  #一个元素
    $rocks[1] = 'slate';  #又一个元素
    $rocks[99] = 'schist';  #现在有97个undef元素

    最后一个元素的索引值

    对数组rocks而言,最后一个元素的索引值是$#rocks,但这个数字比数组元素的个数少1,因为还有一个编号为0的元素。

    $end = $#rocks;  #99,也就是最后一个元素的索引值
    $number_of_rocks = $end + 1;  #100,数组元素的个数
    print $rocks[$#rocks];  #访问最后一个元素

    负数数组索引

    注意:超出数组大小的负数索引值只会得到undef,而不会绕回到数组尾部。

    print $rocks[-1];  #和$rocks[$#rocks]一样,但更简单
    print $rocks[-100];  #得到'bedrock'
    $rocks[-200] = 'crystal';  #致命错误!

    列表直接量

    列表直接量(也就是在程序代码中表示一列数据的写法),可以由小括号内用逗号隔开的一串数据表示,这些数据就称为列表元素。

    (1,2,3)  #包含数字1、2、3这三个数字的列表
    (1,2,3,)  #包含数字1、2、3(末尾的逗号会被忽略)
    ("fred",4.5)  #两个元素,"fred"和4.5
    ()  #空列表——零个元素

    范围操作符(..

    如果是某种规律的序列,不用逐个键入。范围操作符(..)可用于自动创建它两侧标量值之间的所有值。

    (1..100)  #从1到100的整数序列
    (1..5)  #等同于(1,2,3,4,5)
    (1.7..5.7)  #同上,等同于(1,2,3,4,5),小数点部分去掉后取范围
    (0,2..6,10,12)  #等同于(0,2,3,4,5,6,10,12)

    NOTE

    1.范围操作符只能从小到大依次累加

    (5..1)  #得到的是空列表

    2.列表中的元素可以不必都是常数,它们可以是表达式。

    ($m,17)
    ($m+$o, $p+$q)
    ($m..$n)
    (0..$#rocks)  #rocks数组的下标序列

    qw简写

    qw简写可以快速输入,免除反复键入引号和逗号。

    ("fred","barney","betty","wilma","dino")
    等同于
    qw( fred barney betty wilma dino)

    NOTE

    1.qw构建的列表中,Perl都会将其当成单引号内的字符串来处理,所以,不能像双引号内的字符串一样使用 $fred其中的空白字符(如空格、制表符以及换行符)会被抛弃,然后剩下的就是列表中的元素

    所以,上面列表可以写成这样:

    qw( fred 
    barney     betty 
    wilma dino)

     2.因为qw算是一种引用的形式,所以不能将注释放在qw列表中

    qw(
        fred  #abc,在这里加注释会被当成一个元素
        barney
        betty
        wilma
        dino
    )

    3.除了圆括号()Perl还允许用任何标点符号作为定界符,也可以是成对符号

    qw!fred barney betty wilma dino!
    qw/fred barney betty wilma dino/
    qw#fred barney betty wilma dino#
    qw{fred barney betty wilma dino}
    qw[fred barney betty wilma dino]
    qw<fred barney betty wilma dino>

    注意:

    1)如果需要在被圈引的字符串内使用定界符,可通过反斜线转义来引入这个字符。

    qw! yahoo! google ask msn !  #将yahoo!作为一个元素引入

    2)和单引号内的字符串一样,两个连续的反斜线表示一个实际的反斜线。

    qw( This is a \ real backslash);

    列表的赋值

    ▲列表值赋值到变量

    ($fred, $barney, $dino) = ("flintstone", "rubble", undef);

    NOTE

    1.如果变量个数>列表值的个数,多出来的值会被忽略掉

    ($fred, $barney) = qw< flintstone rubble slate granite >  #忽略掉末尾的两个元素

    2.如果变量个数<列表值的个数,多出来的变量会被设成undef(或空列表,后面解释)

    ($wilma, $dino) = qw[flinstone];  #$dino的值为undef

    ▲交换两个变量的值

    ($fred, $barney) = ($barney, $fred);
    ($betty[0], $betty[1]) = ($betty[1], $betty[0]);

    构建一个字符串数组

    ($rock[0], $rock[1], $rock[2], $rock[3]) = qw/talc mica feldspar quartz/;

    引用整个数组(用@字符)

    在赋值操作符两边都可以用

    @rock = qw/bedrock slate lava/;
    @tiny = ();  #空列表
    @giant = 1..1e5;  #包含100000个元素的列表
    @stuff = (@giant, undef, @giant);  #包含200001个元素的列表

    注意:

    1.

    $dino = "granite";
    @quarry = (@rock, "crushed rock", @tiny, $dino);

    这个赋值运算将会把@quarry的值设成拥有5个元素的列表(bedrock, slate, lava, crushed rock, granite),因为@tiny贡献了0个元素给这个列表(注意,由于空列表里没有任何元素,也就不会有undef被赋值到列表中,如果需要undef,也可以显式写明)。

    2.

    列表中的数组名会被展开成(它所拥有的)元素列表,因为数组只能包含标量,不能包含其他数组,所以数组无法成为列表中的元素。

    3.

    就像标量变量的初始值是undef一样,新的或是空的数组的初始值是空列表,即()

    poppush操作符

    pop操作符:提取数组末尾的元素并将其作为返回值

    @array = 5..9;
    $fred = pop(@array);  # $fred为9,@array现在是(5,6,7,8)
    $barney = pop @array;  # $barney为8,@array现在是(5,6,7)
    pop @array;  # @array现在是(5,6),pop的返回值7被抛弃了

    NOTE

    1.最后一行是在“空上下文”中使用pop操作符。所谓空上下文,只不过是表示返回值无处可去的一种说辞。这其实也是pop操作符常见的一种用法,用来删除数组中最后一个元素。

    2.如果数组是空的,pop什么也不做,直接返回undef

    3.pop后面加不加括号都可以。

    push操作符:添加一个(或一串)元素到数组尾端

    @array = (5,6);
    push (@array, 0);  # @array现在是(5,6,0)
    push @array, 8;  # @array现在是(5,6,0,8)
    push @array, 1..10  # @array得到了10个新元素
    @others = qw/5 2 0 y f b/;
    push @array, @others;  # @array又得到了6个新元素(共20个)

    注意:

    pushpop的第一个参数都必须是要操作的数组变量,对列表直接量进行压入(push)或弹出(pop)操作是没有意义的。(因为对列表直接量进行操作后,处理后的列表又怎么表示呢?)

    shiftunshift操作符

    shift操作符:提取数组开头的元素并将其作为返回值

    @array = qw#dino fred barney#;
    $m = shift(@array);  # $m变成"dino",@array现在是("fred", "barney")
    $n = shift @arry;  # $n变成"fred",@array现在是("barney")
    shift @array;  # 现在@array变空了
    $o = shift @arry;  # $o变成undef,@array还是空的

    unshift操作符:添加一个(或一串)元素到数组开头

    unshift(@array, 5);  # @array现在仅包含只有一个元素的列表(5)
    unshift @array, 4;  # @array现在是(4,5)
    @others = 1..3;
    unshift @array, @others;  # @array变成了(1,2,3,4,5)

    splice操作符

    push-popshift-unshift操作符都是针对数组首尾的元素操作的,splice操作符是针对数组中间的元素操作的。

    splice含义:删除操作。

    splice可接受4个参数,后两个参数可选

    splice(参数1,参数2,参数3,参数4)

    参数1要操作的数组

    参数2要操作的一组元素的开始位置(索引值)

    参数3(可选):指定要操作的元素长度(即元素个数)

    参数4(可选):要替换的列表

    接受两个参数:

    @array = qw(pebbles dino fred barney betty);
    @removed = splice @array, 2;  
    #在原来的数组中删掉从fred(索引值为2)开始往后的元素
    #@removed变成qw(fred barney betty)
    #原先的@array变成qw(pebbles dino)

    NOTE

    1.splice返回值是什么? ——删除的元素列表

    2."原地更新"吗? ——是

    接受三个参数

    3个参数作用是指定要操作的元素长度(注意不是结束位置),即元素个数,通过这个参数,可以删除数组中间的一个片段

    @array = qw(pebbles dino fred barney betty);
    @remoed = splice @array, 1, 2;
    #删除dino和fred两个元素
    # @remoed变成qw(dino fred)
    # @array变成qw(pebbles barney betty)

    接受四个参数

    4个参数是要替换的列表,也就是可以补充新元素到原来的数组中,新加入列表的长度不一定要和拿走的元素片段长度一样。

    @array = qw(pebbles dino fred barney betty);
    @remoed = splice @array, 1, 2, qw(wilma);
    #删除dino和fred
    # @remoed变成qw(dino fred)
    # @array变成qw(pebbles wilma barney betty)

    特殊用法

    实际上,添加元素列表并不需要预先删除某些元素,把表示长度的第三个参数设为0,既可不加删除地插入新列表。

    @array = qw(pebbles dino fred barney betty);
    @remoed = splice @array 1, 0, qw(wilma);
    #什么元素都不删除
    # @remoed变成()
    # @array变成qw(pebbles wilma dino fred barney betty)

    注意:

    wilma出现在dino 之前的位置上,Perl从索引值1的地方插入新列表,然后顺移原来的元素

    字符串中的数组内插

    和标量一样,数组的内容同样可以被内插到双引号引起的字符串中。内插时,会在数组的各个元素之间自动添加分隔用的空格

    @rocks = qw( flinstone slate rubble);
    print "quartz @rocks limestone
    ";  #打印5个以空格隔开的单词

    NOTE

    1.数组被内插后,首尾都不会增添额外空格,若真的需要,可以自己手动添加

    2.如果@为双引号内字符串的内容本身时,需引入反斜线转义@或直接用单引号来定义字符串

    $email = "fred@bedrock.edu";  #错!这样会内插@bedrock这个数组
    $email = "fred@bedrock.edu";  #正确
    $email = 'fred@bedrock.edu';  #另一种写法,效果相同

    3.内插数组中的某个元素时,会被替换成该元素的值。

    @fred = qw(hello dolly);
    $y = 2;
    $x = "This is $fred[1]'s place";  #得到This is dolly's place
    $x = "This is $fred[$y-1]'s place";  #效果同上

    4.如果要在某个标量变量后面紧接着写左方括号,需要隔离,否则会被识别为数组引用。

    @fred = qw(eating rocks is wrong);
    $fred = 'right';
    print "this is $fred[3]
    ";  #用到了$fred[3],打印"wrong"
    print "this is ${fred}[3]
    ";  #打印right[3](用花括号避开歧义)
    print "this is ${fred}"."[3]
    ";  #打印right[3](用分开的字符串)
    print "this is $fred[3]
    ";  #打印right[3](用反斜线避开歧义)

    foreach控制结构

    foreach循环能逐项遍历列表中的值,依次提取使用:

    foreach $rock(qw/ bedrock slate lava /){
        print "One rock is $rock.
    ";  #依次打印这三个单词    
    }

    NOTE

    1.每次循环迭代时,控制变量$rock都会从列表中取得新值。

    2.控制变量并不是列表元素的复制品,实际上,它就是列表元素本身。也就是说,假如在循环体中修改了控制变量的值,也就同时修改了列表元素。

    @rocks = qw/ bedrock slate lava /;
    foreach $rock(@rocks){
        $rock = "	$rock";  #在@rocks的每个元素前加上制表符
        $rock .= "
    ";  #同时在末尾加上换行符
    }
    print "The rocks are:
    ",@rocks;  #各自占一行,并使用缩排(注意这种写法,从第二个列表元素开始前面都带一个空格)

    注意:

    @rocks = qw(a b c d);
    print @rocks;  #会得到abcd
    print "@rocks";  #会得到a b c d

    循环结束后,控制变量的值仍然是循环执行之前的值。Perl会自动存储foreach循环的控制变量并在循环结束后还原。

    在循环执行期间,我们无法访问或改变已存储的值,所以当循环结束时,变量仍让保持循环前的值。

    如果它之前从未被赋值,那就仍然是undef

    也就是说,如果想把循环的控制变量取名为$rock的话,不必担心之前是否用过同名的变量。

    $rock = 'shale';
    @rocks = qw/ bedrock slate lava /;
    foreach $rock(@rocks){
        ...
    }
    print "rock is still $rock
    ";  #打印'rock is still shale'

    Perl的默认变量:$_

    假如在foreach循环开头省略控制变量,Perl就会用它最喜欢用的默认变量$_

    这个变量名除了名称比较特别以外,和其它标量变量几乎没什么差别。

    foreach (1..10){  #默认会用$_作为控制变量
        print "I can count to $_!
    ";
    }

    Perl有许多默认变量,$_是最常用的一个,如果不加说明,Perl默认使用$_

    $_ = "Yabba dabba doo
    ";
    print;  #默认打印$_

    reverse操作符

    reverse操作符会读取列表的值(一般来自数组),并按相反次序返回新的列表。

    @fred = 6..10;
    @barney = reverse(@fred);  #返回10,9,8,7,6
    @wilma = reverse 6..10;  #同上,但无需额外的数组
    @fred = reverse @fred;  #倒序后保存到原来的数组

     注意:

    reverse只是返回倒序后的列表,它不会修改给它的参数。加入返回值无处可去,那这种操作也就变得毫无意义。

    reverse @fred;  #错误的用法,这不会使数组内容倒序
    @fred = reverse @fred;  #正确用法

    sort操作符

    sort操作符会读取列表的值(一般来自数组),依次按字符的内部编码顺序对它们排序。

    排序按照ASCII码的大小进行。

    @rocks = qw/ bedrock slate rubble granite /;
    @sorted = sort(@rocks);  #返回bedrock,granite,rubble,slate
    @back = reverse sort @rocks;  #逆序,从 slate 到 bedrock 排列
    @rocks = sort @rocks;  #将排序后的结果存到原数组@rocks
    @numbers = sort 97..102;  #得到100,101,102,97,98,99

    NOTE

    1.按默认排序规则,任何以1开头的字符串会被排在以9开头的字符串之前。

    2.排序操作和reverse操作一样,不会修改原始参数,只是返回新的列表所以要对数组排序,就必须将排序后的结果存回数组。

    each操作符

    Perl 5.12开始,已经可以针对数组使用each操作符了。在这之前each只能用于提取哈希的键-值对。

    每次对数组调用each,会返回数组中下一个元素对应的两个值——数组索引与元素值:

    require v5.12;
    @rocks = qw/ bedrock slate rubble granite /;
    while (($index, $value) = each @rocks){
        print "$index: $value
    ";
    }

    注意:

    这里使用了require,因为使用use v5.12会默认启用“严格(strict)”模式。

    如果不用each,就得根据索引从小到大遍历,然后借助索引取得元素值。

    @rocks = qw/ bedrock slate rubble granite /;
    foreach $index(0..$#rocks){
        print "$index: $rocks[$index]
    ";
    }

    标量上下文与列表上下文

    同一个表达式出现在不同的地方时会有不同的意义。

    所谓上下文,指的是如何使用表达式。

    前文接触过很多针对数字和字符串的上下文操作,比如按照数字进行操作时得到的就是数字结果,按照字符串进行操作时返回的则是字符串结果。而且,起到决定性因素的是操作符,而不是被操作的各种变量或直接量

    2*3  #得到数字6
    2x3  #得到字符串222

    Perl在解析表达式时,要么希望它返回一个标量,要么希望它返回一个列表。

    表达式所在的位置,Perl期望得到什么,那就是该表达式的上下文。

    42 + something  #这里的something必须是标量
    sort something  #这里的something必须是列表

    就算是同一个表达式名称,有时返回的是单个标量值,有时返回的却是列表,这取决于上下文。

    Perl里,表达式总是按照需要的上下文返回对应的值。

    NOTE

    1.以数组的“名称”为例,在列表上下文中返回元素列表,在标量上下文中则返回数组的元素个数

    @people = qw(fred barney betty);
    @sorted = sort @people;  #列表上下文,得到 barney,betty,fred
    $number = 42 + @people;  #标量上下文:42 + 3 得45

    2.即使是普通的赋值操作符(对标量或列表赋值),也可以有不同的上下文。

    @list = @people;  #得到3个人的姓名列表
    $n = @people;  #得到人数3

    3.不要立刻得出结论,认为列表在标量上下文中一定会得到元素的个数而非元素列表。许多能返回列表的表达式会有各种丰富有趣的行为

    4.其实“产生列表”的表达式和“产生标量”的表达式之间并无不同,任何表达式都可以产生列表或标量,根据上下文而定。

    在标量上下文中使用产生列表的表达式

    sort在标量上下文中总是返回undef

    @sorted = sort qw/ fred barney betty /;  #返回barney, betty, fred
    $sorted = sort qw/ fred barney betty /;  #返回undef

    reverse在标量上下文中返回逆序后的字符串(先将列表中所有的字符串全部连接在一起,再对结果中的每一个字符作逆序处理)

    @sorted = reverse qw/ fred barney betty /;  #返回betty, barney, fred

    $sorted = reverse qw/ fred barney betty /;  #返回yttebyenrabderf

    一个典型的例子:

    @array = qw( talc quartz jade );
    if (@array){  #标量上下文中@array返回元素的个数3,表示真
        print "Hello";
    }

    在列表上下文中使用产生标量的表达式

    在列表上下文中,如果表达式求值结果为标量值,则自动产生一个仅含此标量值的列表。

    @fred = 6 * 7;  #得到仅有单个元素的列表(42)
    @barney = "Hello".' '."world";   #得到仅有单个元素的列表('Hello world')

    由于undef是标量值,所以把undef赋值给数组并不会清空数组,得到的还是一个数组,内含一个空值元素。

    @wilma = undef;  #得到的是单个元素的列表,元素值为未定义的(undef)

    要清空数组,直接赋予一个空列表:

    @wilma = ( );  #这才是清空数组的正确方法

    强制指定标量上下文

    在列表上下文中强制引入标量上下文,使用伪函数scalar

    它不是真正的函数,只是用于告诉Perl这里要切换到标量上下文。

    @rocks = qw( talc quartz jade obsidian);
    print "I have ", @rocks, " rocks!
    ";  #得到I have talcquartzjadeobsidian rocks!
    print "I have ", scalar @rocks, " rocks!
    ";  #得到I have 4 rocks!

    列表上下文中的<STDIN>

    在标量上下文中,<STDIN>返回的是输入数据的下一行内容;

    在列表上下文中,返回的则是所有剩下行的内容,一行一个元素,直到文件结尾。

    如果输入数据来自键盘,如何发送结尾标记?

    Unix或类似系统:Ctrl+D

    DOS/WindowsCtrl+Z

    输入完成后,每个元素都是一个以换行符结尾的字符串,因为这些换行符也是输入的内容。

    chomp可以一次性去掉每个元素的换行符:

    写法一:

    @lines = <STDIN>;
    chomp @lines;

    写法二:

    chomp(@lines = <STDIN>);

    如果文件太大,行输入操作符会读取所有行并占用大量内存,所以这时应该选用更合理的方式。

  • 相关阅读:
    202006leetcode刷题记录
    二分查找详解
    并查集
    202005leetcode刷题记录
    基于地震数据的Spark数据处理与分析
    Java日志框架:logback详解
    java 多线程
    Oracle表恢复(truncate)
    关于软件开发,你老板不知道的7件事
    调用oracle 分页存储过程 返回游标数据集
  • 原文地址:https://www.cnblogs.com/yd-yfb/p/13923434.html
Copyright © 2020-2023  润新知