第六章:
什么是哈希?
哈希是一种数据结构,和数组的相同之处在于:可以容纳很多值(没有上限),并能随机存取。而区别在于:不像数组是以数字来检索,哈希是以名字来检索。也就是说检索用的键不是数字,而是保证唯一的字符串。
哈希值得一提的是:虽然这些键是唯一的,但是它们对应的值可以重复。哈希的值可以是数字、字符串、undef,或是这些类型的组合。但是哈希键则全都必须是唯一的字符串。
为什么使用哈希?
可以将一组数据对应到另一组数据。
按名字找姓:
名字可以作为键,而姓可以成为值。这当然需要限定名字是唯一的,如果出现了两个叫做randal的人就行不通了。通过哈希可以按任何人的名字找到相应的姓。例如以tom为值取得值phoenix。
用主机名找IP地址
你也许知道在因特网上,每台计算机同时拥有一个主机名如,以及一个IP地址如123.45.67.89。这因为机器喜欢和数字打交通,但是一般人比较记得名字。主机名是唯一的字符串,可以用来作为哈希的键。通过哈希可以按主机名找到相应的IP地址。
另一种思考方式是将哈希当成极其简单的数据库,其中每个键的“名下”都可以存储相应的数据,事实上只要问题中带有找出重复、唯一、交叉引用、查表之类的字眼,就很有可能会用到哈希。
访问哈希元素: $hash{$some_key} 这和访问数组的做法类似,只是使用了花括号而非方括号来引出索引,而且现的键表达式是字符串,而非数字: $famil_name{"fred"} = "flintstone"; $famil_name{"barney"} = "rubble"; 上面两个也可以整形成下面这个样子: foreach $person (qw< barney fred >) { print "I've heard of $person $family_name{$person}.\n"; }
$foo = "bar"; print $family_name{ $foo . "ney" }; #打印“rubble"
$family_name{"fred"} = "astaire"; #组已有的元素赋上新值
$bedrock = $family_name{"fred"}; #得到"astaire";早先的值已不存在
$family_name{"wilma"} = "flintstone"; #增加一个新的键值对
$family_name{"betty"} .= $family_name{"barney"};
|
访问整个哈希:
要指代整个哈希,可以用百分号(%)作为前缀。因此前面我们使用的哈希应该称为%family_name。
哈希可以被转换成列表,反过来也行。对哈希赋值会带来列表赋值的上下文,列表的元素应该应该是键/值对。
%some_hash = ("foo", 35, "bar", 12.4, 2.5, "hello", "wilma", 1.72e30, "betty", "bye\n");
|
在列表上下文中,哈希会自动变成一些简单的键/值对:
@any_array = %some_hash; 我们把这个变换叫做哈希松绑,将它变成键/值对的列表。当然键/值对也不一定按照当初赋值的顺序松绑。 print "@any_array\n"; #可能会给出下面的结果:
#betty bye (以及一个换行) wilma 1.72e+30 foo 35 2.5 hello bar 12.4
哈希赋值: %new_hash = %old_hash; 更常见的是以某种方式转换哈希,如建立一个反转哈希: %inverse_hash = reverse %any_hash;
|
胖箭头:
在哈希赋值时常常会发现列表中的键/值对并不易区分开来。例如在下面的赋值中,任何人都要逐个扫描列表成员,同时默念着:
键、值,键、值等等
如:
%some_hash = ("foo", 35, "bar", 12.4, 2.5, "hello", "wilma", 1.72e30, "betty", "bye\n"); 如果用胖箭头的方式就很简单了。 my %last_name = ( #哈希也可以是词法变量
"fred" => "flintstone", "dino" => undef, "barney" => "rubble", "betty" => "rubble", );
|
#还有一个瘦箭头->,它是用来服务于引用(reference)的,可以参考perlreftut或者Perlfre了解这个高级话题。
#胖箭头左边的任何祼词都能自动引用,因此胖箭头左边的课词不需要引号。另外哈希键所在的花括号也有类似的自动引用能力。
#裸词的定义是字母、数字和下划线的序列,可以用加号或减号开头,但不能用数字开头。
哈希函数就是围绕哈希很多有用的函数。
keys 和 values 函数:
keys函数能返回哈希的皱列表,而values函数能返回值列表。如果哈希没有任何成员,则两个函数都返回空列表。
my %hash = ("a" => 1, "b" => 2, "c" => 3); my @k = keys %hash; my @v = values %hash;
|
这样@k会包含"a","b"和"c",而@v则会包含1、2和3,当然顺序有所不同,但是可以确定返回的键列表和值列表的顺序是一样的。
my $count = keys %hash; #得到3,也就是说有三对键值
偶尔也能看到别人的程序里把哈希当成布尔表达式来判断真假。
if (%hash) {
print "That was a true value!\n";
}
each 函数:
如果需要罗列哈希的每个键/值对,常见的写法就是使用each函数,它能用两个元素的列表形式返回键/值对。
每次对同一个哈希调用此函数,它就会返回下一组键/值对,直到所有的元素都被访问过,也就是再没有任何新的键/值对,些时
each会返回空列表。
实际使用时,唯一适合使用each的地方就是while循环中,如下所示:
while ( ($key, $value) = each %hash ) { print "$key => $value\n"; }
依次处理哈希的方法: foreach $key (sort keys %hash) { $value = $hash{$key}; print "$key => $value\n"; #或者,可以略去额外的$value变量;
#print "$key => $hash{$key}\n";
}
哈希的典型应用: Bedrock图书馆的借阅信息程序以一个哈希记录每个人借出了几本书: $books{"fred"} = 3; $books{"wilma"} = 1; 判断某项哈希元素的真假: if ( $books{$someone}) { print "$someone has at least one book checked out.\n"; } $books{"barney"} = 0; #现在没有借阅图书
$books{"pebbles"} = undef; #从未借阅过图书,这是张新办的借书卡
exists函数: 检查哈希中是否有某个键(也就是某人是否有借书证)可以使用exists函数,它能返回真或假,分别表示键存在与否。和键的值无关: if (exists $books{"dino"}) { print "Hey, there's a library card for dino!\n"; } delete 函数: delete函数能从哈希中删除指定的键及其相对应的值。假如没有这样的键,它就会直接结束,而不会出现任何警告或错误信息。 my $person = "betty"; delete $books{$person}; #撤回$person的借书卡
哈希值内插: 可以将单一哈希元素内插到双引号引起的字符串中: foreach $person (sort keys %books) { #按次序访问每位借问者
if ($books{$person}) { print "$person has $books{person} items\n"; #fred借了3本书
}
%ENV哈希: Perl程序既然运行在某个环境中,就需要周围的影响有所感知。Perl获取这些信息的方法是存取%ENV哈希。 print "PATH is $ENV{PATH}\n"; 习题: 1、 ======================================================= #!/usr/bin/perl -w
%given_for_first = ( "fred" => flintstone, "barney" => rubble, "wilma" => flinstone); print "Input given_name:\n"; $given_name = <STDIN>;
chomp($given_name); #这里一定要加,开始我没有加,测试了好久都报:Use of uninitialized value in concatenation (.) or string at hash2 line 9, line 1.
$output = $given_for_first{$given_name} ; printf "output firstname is $output"; #my @k = keys %given_for_first;
#my @v = values %given_for_first;
======================================================== #!/usr/bin/perl -w
my $last_name = qw{ fred flintstone barney rubble wilma flintstone }; print "Please enter a first name:"; chomp(my $name = <STDIN>); print "That's $name $last_name{$name}.\n"; ========================================================= 2、 #!/usr/bin/perl -w
my(@words, %count, $word); #声明变量(可以省略)
chomp(@words = <STDIN>);
foreach $word (@words) { $count{$word} += 1; #或者$count{$word} = $count{$word} + 1;
} foreach $word (keys %count) { #或者sort keys %count
print "$word has seen $count{$word} times.\n"; }
========================================================== 3、 #!/usr/bin/perl -w
my $longest = 0; foreach my $key ( keys %ENV ) { my $key_length = length{ $key }; $longest = $key_length if $key_lenth > $longest; }
foreach my $key ( sort keys %ENV ) { printf "%-${longest)s %s\n", $key, $ENV{$key}; }
|
阅读(1129) | 评论(0) | 转发(0) |