Perl零零八速成系列---哈希和子函数
阅读用时:全文共2部分,约4100字,约7分钟
关键词:哈希、子函数、变量操作
在上一节Perl编程课程中,我们介绍了许多常用的函数,比如split函数、join函数等,能够轻松地对数组进行操作,那么问题来了,我们能否自己编写类似的功能函数呢?这个可以有!
今天这节课我们就来学习一下哈希和子函数的相关知识。
《Perl零零八速成系列》(共8节课)主要是面向无Perl编程经验或者Perl语言初学者,介绍Perl的基本知识和实用编程技巧。晨光与你一路,轻松点亮编程技能,一跃成为特工级的Perl编程牛人!
【本节内容】
本节内容包括Perl 语言的哈希和子函数。
1
哈希
上一节课介绍了Perl语言的数据结构和变量基本操作,讲到哈希(hash)是一个无序的key/value(键/值)对集合,可以使用键作为索引获取相应的值,而且每个键是唯一的(如同一个装有各种东西并贴有标签的桶,只不过哈希装的是数据而已,如下图)。那么这节课我们首先就来学习一下哈希的相关操作。
哈希数据桶
PS: 笔者曾经表示好奇,为啥非要比喻成桶而不是其它容器,例如箱子或者篮子什么的,后来想想,可能是参考书的原作者比较喜欢用"桶"这个词吧,此时脑海飘来各种桶…
哈希的赋值
上一节课我们简单地介绍了哈希的赋值,实际上哈希的赋值操作不止一种,而是有多种方式,主要包括:
利用胖箭头赋值
#!/usr/bin/perl
%data = ('google' => 'google.com',
'runoob' => 'runoob.com',
'taobao' => 'taobao.com',
);
print "\$data{'google'} =$data{'google'}\n";
print "\$data{'runoob'} =$data{'runoob'}\n";
print "\$data{'taobao'} =$data{'taobao'}\n";
其中的胖箭头('=>',与表示引用的瘦箭头'->'区分开)表示键与值的对应关系。
PS: 胖箭头赋值的最大好处就是比较清晰和直观。
利用列表赋值
#!/usr/bin/perl
%data = ('google', 'google.com', 'runoob','runoob.com', 'taobao', 'taobao.com');
列表中每两个元素为一对组合,依次为key和value,这种赋值方式的特点就是,当键值对比较多的时候,键和值就没那么好区分了。
PS: 用列表赋值时,宝宝们需要一个个地数 "键、值、键、值…",当哈希的键比较多时,可能会数着数着就睡着了
利用哈希赋值
哈希可以通过一般的赋值语句来进行赋值:
my %new_hash =%old_hash;
另外,还可以通过对现有哈希进行转换得到新的哈希,比如建立一个反序的哈希:
my %inverse_hash= reverse %any_hash;
以上操作会对原有哈希的键-值对进行互换,也就是说原来哈希的值变成了新哈希的键。
PS: 这个操作有一个前提,原哈希的值不能有重复,因为这样新哈希的键会出现重复,会导致后面的键-值对覆盖前面的键-值对。
二
哈希函数
这里我们介绍一些常用的哈希函数:
keys和values函数
keys 函数可以返回哈希的键列表,而values 函数能返回对应的值列表:
#!/usr/bin/perl
%data =('google'=>'google.com', 'runoob'=>'runoob.com','taobao'=>'taobao.com');
@k = keys%data; #@k 包含%data 所有键
@v = values%data; #@v 包含%data 所有值
print"@k\n";
print"@v\n";
运行结果:
runoob taobao google
runoob.com taobao.com google.com
可以看出,@k和@v 中元素的顺序和哈希赋值时的顺序并不相同,而且每次运行以上代码,可能顺序都会不一样,因为哈希的键是无固定顺序的。
PS: 细心的你可能会发现存在一个规律,没错,在每次运行结果中,@k和@v中键和值的顺序是一致的,此时是不是应该在心里给聪明的自己竖起大拇哥呢…
exists 函数
如果要检查哈希中是否存在某个键,可以使用exists函数来判断,返回真或假:
#!/usr/bin/perl
%data =('google'=>'google.com', 'runoob'=>'runoob.com','taobao'=>'taobao.com');
if(exists($data{'facebook'} ) ){
print "facebook 的网址为$data{'facebook'} \n";
}
else
{
print "facebook 键不存在\n";
}
运行结果:
facebook 键不存在
PS: 在上面的一段代码中,我们使用了if(condition){cmd1}else{cmd2}语句,表示如果()中condition为真,就运行前面{}中的cmd1命令,否则运行后面{}中的cmd2命令。
举个🌰:if(好好学习){考上好大学}else{去工地搬砖}。是不是好理解的多?
defined 函数
与exists 函数不同的是,defined函数是用来判断一个变量是否被赋值,例如:
#!/usr/bin/perl
my %hash;
$hash{'a'}=undef; #键 'a' 对应的值为undef,也就是未赋值
if(defined $hash{'a'}){ #判断 $hash{'a'} 是否被赋值
print "\$hash{'a'} was defined.\n";
}else{
print"\$hash{'a'} was not defined.\n";
}
运行结果:
$hash{'a'} was not defined. #说明$hash{'a'} 没有被赋值
PS: 讲到这里是否还有童鞋,对于exists和defined 函数傻傻分不清楚呢?
简而言之,exists 只是判断哈希元素是否存在,无论是否被赋值("有名无分"也行),而defined 则判断元素是否有存在而且被赋值("有名有分"才行)。
delete 函数
如果想删除哈希元素,你可以使用delete 函数:
#!/usr/bin/perl
%data =('google'=>'google.com', 'runoob'=>'runoob.com', 'taobao'=>'taobao.com');
@k1 = keys %data; #之前的所有键
delete $data{'taobao'}; #删除键 'taobao'
@k2 = keys %data; #之后的所有键
print "before: @k1\n";
print "after: @k2\n";
运行结果:
before: taobao runoob google
after: runoob google
each函数
如果想遍历整个哈希的所有键,可以用each函数,它每次被调用可以返回包含一个键-值对的列表,用while循环语句实现遍历哈希所有键:
#!/usr/bin/perl
%data =('google'=>'google.com', 'runoob'=>'runoob.com','taobao'=>'taobao.com');
while ( ($key,$value)=each %data ) {
print " $key => $value\n";
}
运行结果:
google =>google.com
runoob =>runoob.com
taobao =>taobao.com
PS: while 语句中的each函数会遍历哈希的所有键,而且键的顺序是随机的。
2
子函数
什么是子函数
Perl子函数或子程序(subroutine)也就是用户定义的函数,即执行一个特殊任务的一段分离的代码,它可以使减少重复代码且使程序易读。Perl子函数的名称只能由字母、数字和下划线组成(但不能以数字开头),语法格式如下:
#子函数定义:
sub Hello{ #定义子函数名称
print "Hello, World!\n"; #子函数主体代码
}
#子函数调用:
Hello(); #或在函数名前加"&",即&Hello()
运行结果:
Hello, World!
子函数的使用
上述例子介绍了子函数的基本语法,理解起来比较简单,但是子函数在具体使用过程中,会涉及到参数传递、返回值以及变量的私有性等问题,下面我们就一一介绍。
子函数的参数
和其他编程语言一样,Perl子函数也可以接受1个或多个参数,子函数参数使用特殊数组 @_ 标明。因此子函数第一个参数为 $_[0], 第二个参数为 $_[1], 以此类推,例如:
#!/usr/bin/perl
sub Average{ # 定义求平均值函数
$n = scalar(@_); # 获取所有传入参数的个数
$sum = 0;
foreach $item (@_){ # 遍历所有传入的参数
$sum += $item; # 利用 '+=' 运算符计算数字之和
}
$average = $sum / $n;
print '传入的参数为 :',"@_\n"; # 打印整个数组
print "第一个参数值为 :$_[0]\n"; # 打印第一个参数
print "传入参数平均值为 :$average\n"; # 打印平均值
}
Average(10, 20, 30); # 调用函数
运行结果:
传入的参数为 : 10 20 30
第一个参数值为 : 10
传入参数平均值为 : 20
子函数的返回值
子函数可以使用return语句来返回函数值,如果没有使用return语句,则子函数的最后一行语句将作为返回值:
#!/usr/bin/perl
# 方法定义
sub add {
$_[0]+$_[1]; #不使用 return,返回最后一行执行语句的值
# return $_[0]+$_[1]; # 使用 return,返回指定的值
}
print add (1, 2)
运行结果:
3
子函数的私有性变量
默认情况下,Perl中所有的变量都是全局变量,这就是说变量在程序的任何地方都可以调用。如果我们只希望变量在某个局部被调用,需要设置私有变量,这时可以使用my(表明是特定区域专属的)操作符来设置作用区域。例如:
#!/usr/bin/perl
$string = "Hello,World!"; #全局变量
sub PrintHello{
my $string; #PrintHello 函数内定义的私有变量
$string = "Hello, Runoob!";
print "函数内字符串:$string\n";
}
PrintHello(); #调用函数
print "函数外字符串:$string\n";
运行结果:
函数内字符串:Hello, Runoob!
函数外字符串:Hello, World!
PS: 通过my 创建的变量,有效区域只限于从声明开始的地方,到闭合作用域的结尾。闭合作用域可以是一对花括号{}中的区域,比如一个 if, while, for, foreach等语句的{}中。
本文尽量精简地介绍了Perl语言中哈希的基本操作和子函数的使用,并配上简单的示例供大家练习巩固。由于篇幅有限,难以深入展开说明,谨以此文,送与初入门Perl语言的朋友们。
下一节课,我们来介绍介绍perl语言中最亮眼的一部分:正则匹配,敬请大家关注!
参考资料:
《Perl语言入门第六版(中文版)》
http://www.runoob.com/perl/perl-tutorial.html
http://www.runoob.com/try/runcode.phpfilename=HelloWorld&type=perl
【完】
作者原创作品,未经授权禁止转载!
扫码关注,获取更多精彩内容
我
是
彩
蛋
关注公众号后:
回复文字:好好学习,收听喜马拉雅FM电台栏目《一分钟听懂NGS基础概念》,让生信分析不再遥不可及。
回复文字:果然科学,给你看一篇好玩的科普文章。