Perl Learning (6) —— 哈希

    技术2024-10-17  55

    2011-02-07 wcdj

     

    (1) 什么是哈希? (2) 为什么使用哈希? (3) 访问哈希元素 (4) 访问整个哈希 (5) 哈希赋值 (6) 胖箭头 (7) 哈希函数 (1) 什么是哈希? 哈希是一种数据结构。以前叫它关联数组(associative array),由于太啰嗦,于是改名为哈希(hash)。 数组和哈希的区别: 相同点:可以容纳很多值(没有上限),并能随机存取。 不同点:不像数组是以数字(下标)来检索,哈希是以名字(唯一的字符串)来检索。 注意: [1] 在哈希里没有顺序(从而保持高速检索的能力),有的只是一些键(字符串)/值对。 [2] 某些语言的哈希实现在键/值对增多时会逐渐变慢(例如awk),但是对于Perl都是一样快的。 [3] 哈希的值可以任意,但是哈希的键则全都必须是唯一的字符串。 [4] 哈希是从键到值的单行道。 (2) 为什么使用哈希? 创意的根源:需要将一组数据对应到另一组数据。 另一种思考方式:是将哈希当成极其简单的数据库,其中每个键的“名下”都可以存储相应的数据。 (3) 访问哈希元素 访问哈希元素的语法:$hash{ $some_key }

    #!/usr/bin/perl $name{"ID1"} = "wcdj"; $name{"ID2"} = "gerry"; print "$name{ID1}/n";# wcdj print "$name{ID2}/n";# gerry foreach $person (qw< ID1 ID2 >) { print "$name{$person}/n"; }

    注意: [1] 这和访问数组的做法类似,只是使用了花括号而非方括号来引出索引。 [2] 若对某个已存在的哈希元素赋值,就会覆盖之前的值。 [3] 哈希元素会因赋值而诞生。 [4] 访问哈希表里不存在的值会得到undef。

     

    (4) 访问整个哈希 要指代整个哈希,可以用百分号(%)作为前缀。 哈希可以被转换成列表,反过来也行。对哈希赋值会带来列表赋值的上下文,列表的元素应该是键/值对。 %some_hash = ( "wcdj", "C++", "gerry", "perl", "yj", "python", "echo" ); foreach $person (qw< wcdj gerry yj echo >) { print "$some_hash{$person}/n"; } @any_array = %some_hash;# 哈希松绑,将哈希变成键/值对的列表 print "@any_array/n"; $end = $#any_array;# 最后一个元素的索引 $number_of_any_array = $end+1;# 数组的个数 print "$number_of_any_array/n";# 8 foreach (@any_array) { print "$_/n"; }

    注意:哈希键所在的花括号具有自动引用能力,因此,裸词不需要引号。 PS: 裸词的定义:字母、数字和下划线的序列,可以用加号或减号开头,但不能用数字开头。

     

    print "自动引用/n"; %some_hash = ( wcdj, "C++", gerry, "perl", yj, "pytihon", echo ); foreach $person (qw< wcdj gerry yj echo >) { print "$some_hash{$person}/n"; }

     

    (5) 哈希赋值 print "哈希赋值/n"; %new_hash = %old_hash; @array = %new_hash;# 哈希松绑,将哈希变成键/值对的列表 print "@array/n";

    其实%new_hash = %old_hash;这一行代码会导致%old_hash松绑成为键/值对的列表,然后通过列表赋值重新构造每个键/值对,最终形成哈希%new_hash。 更常用:建立一个反转哈希­ —— 导致键值互换。 print "反转哈希/n"; %inverse_hash = reverse %some_hash; @array = %inverse_hash;# 哈希松绑,将哈希变成键/值对的列表 print "@array/n";

    注意:这种技巧只能在哈希值唯一的情况下才能奏效,否则就会导致重复的键,而这对于哈希是不可能的。对于这个问题,Perl采用“后发先至”的原则,用列表最后的键覆盖之前的键。但是,键/值对在哈希松绑之后的顺序是无法预知的,所以也无法预知哪个键会被覆盖。因此,这个技巧最好是在确定原哈希的值唯一的情况下使用。 (6) 胖箭头 Perl为了让列表中的键与值成对组合,方便区别谁是谁,发明了“胖箭头(=>)”。 注意:对于Perl而言,它只是逗号的另一种写法,因此,常常称呼它为“胖逗号”。也就是说,在任何需要逗号的地方都可以用胖箭头代替,这对Perl来说没什么区别 —— 一个细微的差别是:胖箭头左边的任何裸词都能自动引用,因此,胖箭头左边的裸词不需要引号。 PS: 裸词的定义:字母、数字和下划线的序列,可以用加号或减号开头,但不能用数字开头。

    print "胖箭头/n"; my %some_hash = ( "wcdj" => "C++", "gerry" => "Perl", "yj" => "Python", "echo" => , ); foreach $person (qw< wcdj gerry yj echo >) { print "$some_hash{$person}/n"; } print "自动引用/n"; my %some_hash = ( wcdj => "C++", gerry => "Perl", yj => "Python", echo => , ); foreach $person (qw< wcdj gerry yj echo >) { print "$some_hash{$person}/n"; }

     

    (7) 哈希函数 [1] keys和values函数 keys函数能返回哈希的键列表。 values函数能返回值列表。 注意:如果哈希没有任何成员,则两个函数都返回空列表。 print "哈希函数/n"; my %some_hash = (wcdj=>"C++",gerry=>"Perl",yj=>"Python"); # 输出C++ /n Perl /n Python /n foreach $person (qw< wcdj gerry yj >) { print "$some_hash{$person}/n"; } my @k = keys %some_hash; print "@k/n";# wcdj gerry yj my @v = values %some_hash; print "@v/n";# C++ Perl Python

    注意:在标量上下文中,这两个函数都会返回哈希中键/值对的个数。 #my @k = keys %some_hash; my $k_cnt = keys %some_hash; print "$k_cnt/n";# 3 #my @v = values %some_hash; my $v_cnt = values %some_hash; print "$v_cnt/n";# 3

     

    注意:将哈希当成布尔表达式来判断 。只要哈希中有一个键/值对,就会返回真。 %hash; if (%hash) { print "That was a true value!/n"; } else { print "empty hash!/n" }# 输出这句 %hash = ( wcdj=>"C++",gerry=>"Perl",yj=>"Python" ); if (%hash) { print "That was a true value!/n";# 输出这句 } else { print "empty hash!/n" }

     

    [2] each函数 如果需要罗列哈希的每个键/值对,常见的写法就是使用each函数(另一种常见的方法是用foreach)。 它能用两个元素的列表形式返回键/值对。每次对同一个哈希调用each函数,它就会返回下一组键/值对,直到所有的元素都被访问过。 注意:实际使用时,唯一适合使用each的地方就是在while循环中。 my %my_hash = ( "wcdj"=>"C++","gerry"=>"Perl","yj"=>"Python" ); print "each函数/n"; while ( ($key, $value) = each %my_hash ) { print "$key => $value/n"; }

     

    使用foreach的等价方法:

    print "foreach方法/n"; my %my_hash = ( "wcdj"=>"C++","gerry"=>"Perl","yj"=>"Python" ); foreach $key (keys %my_hash) { $value = $my_hash{$key}; print "key => $value/n"; # 或者简写 print "key => $my_hash{$key}/n"; }

     

    最新回复(0)