Perl学习笔记 数组/散列(哈希)

数组

数组中的每个元素都是单独的标量变量,并且是有序的,我们可以通过数组索引对其赋值

@array = ()定义空数组,$#array表示数组最后一次元素的索引值,$array[0]表示数组第一个元素以及$array[-1]表示数组最后一个元素等

怎么理解数组是有序这个意思呢,比如我想将有三个元素的数组赋值于一个只有两个元素的数组,那么后面的数组的第三个元素将自动被忽略,如下:

($one, $two) = ("aaa", "bbb", "ccc");

或者这么理解:

@array[2,3] = ("a", "bb");

对数组操作的话,有几个操作符:

  • push/pop操作符

    push是将元素(或者数组)加到一个数组的尾端

    push @array, 1;
    push @array, @tmp;
    

    pop则相反,是取出数组中最后一个元素

    pop @array;
    $a = pop @array;
    
  • shift/unshift操作符

    这两个跟上面两个操作符相反,是处理数组开头的,比如shift是将数组的前一个元素取出

    shift @array;
    

    常与@ARGV搭配可一个个取出perl程序的输入参数

    @file = shift @ARGV;
    

    unshift则是跟shift相反操作,可将元素(或者数组)加到一个数组的开头

    unshift @array, @tmp;
    
  • 其实我觉得最好用的还是splice这个操作符,理论上行splice可以代替上面所有的操作符的功能,但是有些出于习惯和方便的原因,可能不会选择用splice代替

    splice操作符可以接收4个参数,前两个是必须参数,后两个是可选参数。第一个参数当然是需要处理的数组@array,第二个参数为要操作的起始位置,第三个参数是操作的元素长度,第四个参数是要替换的列表(数组)。我们可以灵活使用这4个参数来对数组进行各种操作

    splice ARRAY, OFFSET, LENGTH, LIST
    

    对于splice的理解可以分为两部分,首先看是否赋值于新数组,比如下面两个代表着两个不同的意思

    splice(@array, 2);
    @result = splice(@array, 2);
    

    前者表示删除@array数组的第3个元素到最后一个元素,后者表示将@array的第3个元素到最后一个元素赋值于@result数组(当然,@array数组其实也发生了删除元素的步骤,切记!!)

    接着可以按照splice操作符使用了几个参数来分不同的作用,比如删除第3个到第5个元素或删除第3个元素

    splice(@array, 2, 3);
    splice(@array, 2, 1);
    

    在数组第3个位置增加一个元素or数组

    splice(@array, 3, 0, "add");
    splice(@array, 3, 0, @add);
    

    如果是替换元素呢,其实跟上述增加元素的用法是差不多的,比如用@repeat数组替换@array数组的第3到5个元素

    splice(@array,2,3,@repeat);
    

    还有以下几点需要注意的,下面这个表示返回最后一个移出的值,也就是返回@array数组的第5个元素

    $result = splice(@array, 2, 3);
    

    如果第三个参数为负数,那么第三个参数不再代表长度了,而是表示位置,如下表示移出第3个元素到最后一个元素

    splice(@array, 2, -1);
    

    如果第二个参数为负数,那么起始的位置不再是数组从头到尾了,而是从尾端的某个元素开始,如下表示移除数组@array最后2个元素

    splice(@array, -2);
    

散列(哈希)

Learning Perl这本书中称其为哈希,在Intermediate Perl这本书中则叫其为散列,当然其实我觉得还是散列更加贴切点,跟数组相对应嘛。散列是一种数据结构,能储存任意多的键以及其所对应的值,跟数组的的区别在于索引方式,散列是以”名字”来当做索引的,也称为键,键对应的储存数据则称为值。当然由于散列的键是字符串,所以在散列里面储存的数据是没有顺序的。不夸张的说,有散列的perl和没有散列的perl完全不是同一层次的语言。。。。个人觉得,因为其实在太好用了。。。。

散列中的键是必须唯一的,这跟数组的索引一样,%hash可以被这样赋值:

%hash = (key, value, key, value, key, value);

可以通过reverse将%hash的键和值互换

%reverse_hash = reserve %hash;

其实一般是以胖箭头

%hash = (
    a => "aaa",
    b => "bbb",
);

可看到键没有给予引号,这是因为perl默认许可键如果是单纯的字符串是不同给引号的,比如

%hash{a} = 1;

但是不是单纯的字符串,而是表达式或者其他连接形式的话,则最好加引号,反正我徒省事,不然咋样都加引号,比如下面2个就是不同的键,前者键为aabb,后者键为aa.bb

%hash{aa.bb} = 1;
%hash{"aa.bb"} = 1;
  • 如果想提取%hash的键和值,可以用keys函数和values函数,如果想对键排序则可再加上sort函数

    @array = sort keys %hash;
    @array = values %hash;
    
  • 当然如果想对每一对键-值进行处理,则可以使用each函数遍历散

  • 列,而且其会记得每个上一次返回的是哪个键-值,所以其能迭代整个散列。但是如果散列重置(读取了所有元素,或者使用了keys %hash or values %hash)后,那么顺序会再次改变了

    while(my ($k, $v) = each(%hash)){  
        print "$k  =>  $v\n";
    }
    

    其实我也很少用each函数,因为如果是遍历整个散列,我会使用foreach搭配key函数,因人而异了

    foreach (keys %hash){
        print "$_  =>  $hash{$_}\n";
    }  
    
  • 判断散列的键是否存在用exists函数,但我一般用if语句根据$hash{$key}对应的值是否为空来判断键$key是否存在,如下两个写法大部分时候是等价的

    if (exists $hash{$key}){
        print "xxx";
    }
    
    if ($hash{$keys}){
        print "xxx";
    }   
    

    但是delete函数还是蛮有用的,可以删除特定的键,当然也顺便也删除了该键对应的值

    delete $hash{$key}; 
    

切片

除了上述对数组和散列的操作外,还有一个比较重要的是切片,我喜欢用分割来理解,即将一个标量分割为一个数组,如下:

@array = split //;

上述默认的写法即是将$_变量按照每个字符进行分割,其实split在文件处理中,处理tab分割的每行数据更加好用

@array = split /\t/, $line;

其实perl对切片的定义是比较广的,下述这种也叫做切片

$array[0,1] = ($one, $two);

所以我们经常会看到这样的用法

($one, $two) = (split /\t/, $line)[0,1]

除了对数组进行切片,当然还有散列(哈希)的切片,我觉得这个非常强大!可惜总是忘记使用。。。

@array = @hash{@info}

那么要表达的就是提取出@info数组中的所有元素在%hash中作为键对应的值,并赋予数组@array;上述的复杂的写法则如下,两者的水平已经不是同一层次了。。。

foreach my $k (keys %hash) {
    if (grep{$k eq $_}@info) {
        push @array, $hash{$k};
    }
}

本文出自于http://www.bioinfo-scrounger.com转载请注明出处