Perl学习笔记3——哈希

哈希的概念与性质

哈希是Perl中的第三种数据结构,又称关联数组。其与数组具有一定的相似性,许多特性可以与数组形成类比。哈希同数组一样,可以容纳任意多的元素并按需取用。

哈希与数组最大的不同之处在于索引方式。在数组中,数组元素以索引值来索引,而在哈希中,用于索引的是一个任意的字符串,这个字符串就称为哈希键,其对应的值就称为哈希值。所以哈希就是由许多哈希键-值对所组成的一个数据集合。

哈希键具有唯一性,即在一个哈希中,不可能出现两个相同的哈希键。但哈希键所对应的哈希值是可以重复的。

哈希具有无序性,也可以理解为乱序性,这是哈希区别于数组的一大重要特点。在哈希中,不存在哈希键-值对的先后顺序,即不存在“第n个哈希元素”这样的说法,只存在哈希键与哈希值之间的一一对应关系。并且Perl出于特殊需要,还会在某些情况下刻意重排哈希中键-值对的先后顺序。

访问整个哈希与哈希赋值

类似于数组中的@,如果要指代整个哈希,可以使用百分号%作为限定符,后接哈希名称。哈希名称也属于Perl标识符的一种,有其独立的名字空间。哈希与列表可以相互转换,所以对整个哈希赋值就可以通过列表来完成。在给哈希赋值的列表中,列表的第一、二个元素分别是一个哈希键及其对应的哈希值,第三、四个元素分别是下一对哈希键-值对,以此类推。下例为一个对整个哈希赋值的示例程序:

%hash=qw/a aaa b bbb/;    #对整个哈希%hash赋值,存入两个键-值对:a对应aaa、b对应bbb

在Perl中,胖箭头“=>”就是逗号的另一种写法,所以在列表中,其可以发挥和逗号一样的作用,即分隔多个列表元素。所以如果将列表中哈希键-值对之间的逗号换为胖箭头,就能更加清晰直观地体现出键-值对的对应关系。胖箭头的另一个作用为可以隐式引起胖箭头左边的字符串,从而省略左边字符串的引号。而如果左侧字符串为表达式,则其会被先计算,再被隐式引起。

在使用胖箭头时,应注意左边未加引号的部分是否出现了会引起歧义的符号,如加号,乘号等,如果出现这种情况,则左边的字符串必须显示引起。例:

%hash=(

a=>'aaa',

b=>'bbb',

c=>'ccc',

);          #用含有胖箭头的列表给哈希赋值

在列表上下文中,哈希会展开为一个含有键-值对的列表。这一操作称为展开哈希。例:

@n=%hash;   #展开哈希,并将其赋值给数组

哈希也可以赋值给哈希,右边的哈希会先展开成键-值对列表,然后将此列表赋值给哈希。常见的操作如复制一个新哈希或建立反序哈希。例:

%new_hash=%old_hash;    #复制哈希

%hash=reverse%hash;      #建立反序哈希

所谓反序哈希,即将哈希展开为键-值对列表后,对列表进行反序,然后再赋值给哈希。这样的操作会颠倒每一对键-值对的顺序,使原来的键变为值,而使原来的值变为键。显然,这种操作不适用于哈希值有重复的情况,因为这样会导致颠倒后哈希键的重复。当重复的键又一次被赋值时,后值会覆盖原先的值,并且由于哈希的无序性,也无从得知是哪一个值在前哪一个在后。

在标量上下文中,非空哈希会返回一个类似分数的字符串,供内部调试使用,而空哈希会返回0,所以普通用户可以将其当作布尔值使用,用以判断哈希是否为空。

访问哈希元素与哈希元素内插

要访问单个哈希元素,就可以使用$开头表示调用单个值,后接哈希名称,再后接用一对花括号围住的哈希键。由于哈希键是字符串,所以原则上应使用引号引起,但在实际操作中,如果没有歧义产生,绝大多数情况下花括号内的哈希键引号均可省略。如果花括号内为表达式,则该表达式会被计算。例:

$hash{b}                     #调用键为b的哈希值

for(qw/a b c/){print$hash{$_}}    #使用$_循环迭代键列表,并输出键为$_的哈希值,“$_”这个表达式在调用哈希时会先被计算

类似于列表中对单个元素的赋值,哈希中对单个哈希键赋值也可以通过调用单个哈希元素这种方式。例:

$hash{b}=bbb;    #对哈希键b进行赋值,省略了字符串引号

哈希元素也可以进行双引号内插。但只能内插单个哈希值,而不能内插整个哈希。内插整个哈希时,不会产生任何效果,百分号会被当作字符串处理。例:

for(qw/a bc/){print"$_=>$hash{$_}\n"}   #双引号内插哈希值

print"%hash";                         #无任何效果,结果就是"%hash"

keysvalues函数

Perl中有许多的函数可以用于处理哈希。keys函数是最常用的哈希函数之一,其参数为一整个哈希,可以返回此哈希的键列表。例:

@n=keys%hash;                #返回%hash的键列表,并存入@n中

for(keys%hash){print$hash{$_}}    #首先由keys返回%hash的键列表,然后遍历所有键,并输出哈希值

values函数与keys类似,其可以返回哈希值列表。例:

@m=values%hash;    #返回%hash的值列表,并存入数组m中

当一个哈希中新增键-值对时,哈希元素的先后顺序会被重排,而其他情况,如修改哈希值、删除键-值对或调用哈希函数等均不会使哈希元素重排,这就是哈希重排的规则。所以当同时使用keys和values函数返回两个列表时,会发现这两个列表中键-值对的顺序是一一对应的。

在标量上下文中,这两个函数都会返回列表元素个数,即哈希中键-值对的数量。例:

$_=keys%hash;    #$_的值即哈希中键-值对的数量

哈希排序初步

由于哈希的无序性,哈希本身是无法排序的。而所谓的哈希排序,本质上就是利用哈希键的唯一性,按一定的规则对哈希键列表进行排序,从而得到一个排序后的键列表,然后再通过键与值之间的对应关系来处理哈希值。

所以在哈希排序时,可以先使用keys函数取出哈希键列表,再使用排序函数sort对这个列表进行排序,从而得到一个排序后的哈希键列表。例:

for(sortkeys%hash){print"$_=>$hash{$_}\n"}

上例中,首先用keys函数取出哈希键列表,此列表作为sort函数的参数进行排序,这样就得到了排序后的哈希键列表。这个列表再作为foreach循环的参数进行循环迭代,最终输出的便是以排序后的键列表的顺序调用的哈希键-值对。

each函数

类似于foreach循环,如果需要遍历哈希中的每一对键-值对,除了用keys取出键列表进行循环外,还可以使用each函数。each函数实际上是一个作用于列表的函数,即作用于哈希展开得到的列表。每次对列表调用此函数时,each都会返回列表中的下两个元素形成的列表。而对哈希使用时,这两个元素就是一对哈希键-值对。在实际使用中,唯一适合使用each函数的地方就是在while循环的条件表达式中。每循环一次,each函数会从哈希中取出下一个键-值对,从而执行代码块。例:

while(($n,$m)=each%hash){print"$n=>$m\n"}

上例的机制比较复杂。首先,each函数从哈希中取出一对键-值对,然后赋值给列表。由于while的条件表达式是布尔上下文,即一种特殊的,返回布尔值的标量上下文,所以列表会返回列表中元素的个数2,判定为布尔真值,所以执行循环。当each迭代到哈希的末尾时,则会返回一个空列表并赋值,而空列表由于没有元素,所以在布尔上下文中返回0,即布尔假值,从而跳出循环。

每一个哈希都含有一个自己独立的迭代器,用于记忆上一次循环所访问的位置,从而使each能每次取出下一个键-值对。在某些情况下,迭代器会被重置。

existsdelete函数

exists函数可以检查哈希中是否存在指定的键,如存在,则返回真值,常用于条件表达式中。这个函数仅检查哈希键的存在与否,与哈希值的真假无关,可以理解为该键是否能出现在keys返回的列表中。例:

if(exists$hash{b}){print'T'}else{print'F'}    #检查是否存在$hash{b}这个键

delete函数可以从哈希中删除指定的键-值对。如果哈希中不存在这样的键值对,则会直接略过。例:

delete$hash{b};    #删除键为b的这个键-值对




樱雨楼

完成于2016.1.3

最后修改于2016.1.26

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容