Perl学习之哈希hash

本文介绍了哈希这种数据结构的基本概念,包括如何存储和检索数据、常见的哈希操作以及哈希函数的应用。通过实例展示了哈希在编程中的实用性和灵活性。

一、什么是哈希
哈希是一种数据结构,和数组类似,可以将值存放到其中,或者从中取回值。但是,和数组不同的是,其索引不是数字,而是名字。也就是说,索引(这里,我们将 它叫key)不是数字而是任意的唯一的字符串。
key可以是任意的字符串,你可以使用任何的字符串作为key,但它们是唯一的。
另一种思考hash 的方法是,把它看作一堆数据(a barrel of data),每一个数据都有一个相应的标签。可以通过标签访问此标签对应的元素。但其中是没有第一个元素的概念的。在数组中,数组元素从0,1,2 开始编号。但在hash中,没有确定的顺序,因此也没有第一个元素。只是一些key/value 对的集合。
keysvalues均为任意的标量,但keys通常转换为字符串。因此,如果将表达式50/20 作为keys,则其通常被转换为3字符的字符串“2.5”
由于Perl没有不必要的限制的设计哲学:hash可以是任意大小,从空hash(没有key/value),到任何你内存允许的大小。
keys是唯一的,但values可以重复。hashvalue可以是数字,字符串,undef,或者它们的混合,但key是唯一的。
为什么使用Hash
可以把hash看作一个简单的数据库,其中每一个key下面可以有一块数据。如果你的任务是关于:查询重复的唯一的交叉引用的查询表,则hash很可能在这类应用中帮上你的忙。
二、哈希元素的存取
要访问hash 元素,可以使用下面的语法:
$hash{$some_key}
这和访问数组元素的方法有些类似,这里下标(key)上使用的是花括号({}),而不是方括号([ ])。现在key 的表达式是字符串,而非数字
hash的名字和Perl中其它的标识符的命名规则是一样的(字母,数字,下划线组成,但不能由数字开头)
访问不存在的hash元素将得到undef
1.作为整体的hash
要引用整个hash,使用百分号(%)作为前缀。
为了方便,hash可以转换为列表,或者反过来。
2.Hash 赋值
可以使用如下的语法在hash 之间拷贝:
%new_hash = %old_hash;
hash转变成其它形式更加常见。例如,我们可以将hash反转:
%inverse_hash = reverse %any_hash;
3.
大箭头符号(=>)
当给hash赋值时,有时并不明显哪些元素是keys,那些是values,因此发明了大箭头符号(=>)。在需要逗号的时候,都可以使用大箭头符 号替换。
如:
my %last_name = (
"www" => 1,
"eee" => 2,
);

三、哈希函数
某些有用的函数可以对整个hash 进行操作。
1.keysvalues函数
keys函数会返回此hash的所有keysvalues函数将返回所有的values。如果hash中没有元素,则此函数将返回空列表。
my %hash = ("a"=>1, "b"=>2, "c"=>3);
print my @k = keys %hash;
print my @v = values %hash;
2.each
函数
如果想迭代hash的每一个元素,一种通常的方法是使用each函数,它将返回key/value对应的2个元素列表。
当对同一个hash 函数进行一次迭代时,将返回下一个key/value对,直到所有的元素均被访问。如果没有更多的key/value对,则each函数将返回空表。
my %hash = ("a"=>1, "b"=>2, "c"=>3);
while(($key, $value) = each %hash)
{
        print "$key => $value/n";
}
当然,each返回的key/vlaue对,顺序是混乱的(它其顺序和keysvalues函数返回的顺序相同)。如果想将其按序排放,可以对它们排序 (使用sort)。
my %hash = ("a"=>1, "b"=>2, "c"=>3, "d"=>4);
foreach $key (sort keys %hash)
{
        $value =$hash{$key};
        print "$key => $value/n";
}
四、哈希的通常用法
1.exists函数
要查看hash中是否存在某个key,可以使用exists函数,如果hash中存在此key,则返回true,与是否有对应的value无关。
my %hash = ("a"=>1, "b"=>2, "c"=>3, "d"=>4);
if(exists $hash{'a'})
{
        print "true";
}
2.delete
函数
delete函数将某个给定的key(包括其对应的value)hash中删除。如果不存在这个key,则什么也不做,不会有警告或者错误信息。
my %hash = ("a"=>1, "b"=>2, "c"=>3, "d"=>4);
delete $hash{'a'};
foreach $key (sort keys %hash)
{
        $value =$hash{$key};
        print "$key => $value/n";
}
3.hash
元素的内插
你可以在双引号的字符串中使用单个hash元素,但不支持整个hash 的内插。
my %hash = ("a"=>1, "b"=>2, "c"=>3, "d"=>4);
foreach $key (sort keys %hash)
{
        print "$key => $hash{$key}/n";
}

 

http://blog.chinaunix.net/u2/70049/showart_1165779.html

<think> 我们正在讨论Perl中遍历哈希的方法。根据用户的问题,结合站内引用,我们可以总结出以下几种遍历方式: 1. 使用`each`函数:这是Perl中专门用于遍历哈希的内置函数,每次调用返回一个键值对。 示例代码: ```perl my %hash = ("a" => 1, "b" => 2, "c" => 3); while (my ($key, $value) = each %hash) { print "$key => $value\n"; } ``` 注意:`each`函数会依次返回哈希中的每个键值对,直到遍历完所有元素。在遍历过程中修改哈希(如添加或删除元素)可能会导致可预期的结果,因此应避免在遍历时修改哈希。 2. 使用`keys`函数获取所有键,然后遍历键并获取对应的值: ```perl my %hash = ("a" => 1, "b" => 2, "c" => 3); foreach my $key (keys %hash) { my $value = $hash{$key}; print "$key => $value\n"; } ``` 这种方法先获取所有的键,然后对每个键查找对应的值。如果需要按特定顺序遍历,可以在`keys`函数前进行排序,例如: ```perl foreach my $key (sort keys %hash) { ... } # 按键的ASCII顺序排序 ``` 3. 使用`values`函数直接遍历值(如果需要键): ```perl foreach my $value (values %hash) { print "$value\n"; } ``` 注意:这种方法只能获取值,无法同时获取键。而且值的顺序和键的顺序一样是确定的。 4. 在嵌套哈希中遍历多层结构(例如哈希哈希): ```perl my %hash = ( "department1" => { "Alice" => 100, "Bob" => 90 }, "department2" => { "Charlie" => 85, "David" => 95 } ); # 遍历外层哈希的键(部门) foreach my $dept (keys %hash) { # 内层哈希引用 my $inner_hash_ref = $hash{$dept}; # 遍历内层哈希的键(姓名) foreach my $name (keys %{$inner_hash_ref}) { my $score = $inner_hash_ref->{$name}; print "$dept: $name => $score\n"; } } ``` 5. 使用`map`函数进行转换(虽然是直接遍历输出,但可以用于处理哈希元素): ```perl my @pairs = map { "$_ => $hash{$_}" } keys %hash; print join("\n", @pairs); ``` 注意事项: - 哈希遍历的顺序是确定的(与插入顺序无关),除非显式使用排序。 - 在遍历过程中要修改哈希结构(增删键),否则可能导致可预测的行为。 - 如果需要同时操作键和值,`each`函数效率较高,因为它需要预先构建整个键列表。 以上方法在站内引用中也有体现,例如引用[5]展示了使用`each`和`keys`的方法,引用[3]展示了嵌套哈希的遍历[^3][^5]。 §§相关问题§§ 1. Perl中如何按值对哈希进行排序并遍历? 2. 在Perl中遍历哈希时如何避免修改哈希结构? 3. Perl的`each`函数在遍历过程中有哪些限制? </think> 在 Perl 语言中,遍历哈希主要有以下几种方法,每种方法适用于同场景: ### 1. 使用 `each` 函数(推荐高效方式) ```perl my %fruit = (apple => 3, banana => 5, orange => 2); while (my ($key, $value) = each %fruit) { print "$key: $value\n"; } # 输出: # apple: 3 # banana: 5 # orange: 2 ``` - **优点**:内存效率高,每次只取一对键值 - **注意**:遍历过程中修改哈希可能导致可预测结果[^5] ### 2. 使用 `keys` 函数遍历键 ```perl foreach my $key (keys %fruit) { print "$key => $fruit{$key}\n"; } ``` - **排序键**:添加 `sort` 实现有序遍历 ```perl foreach my $key (sort keys %fruit) { print "Sorted: $key => $fruit{$key}\n"; } ``` ### 3. 使用 `values` 函数直接遍历值 ```perl foreach my $val (values %fruit) { print "Value: $val\n"; } # 输出: # Value: 3 # Value: 5 # Value: 2 ``` - **限制**:无法获取对应键名 ### 4. 嵌套哈希遍历(多层结构) ```perl my %department = ( IT => { Alice => 5000, Bob => 6000 }, Finance => { Carol => 7000, Dave => 5500 } ); foreach my $dept (keys %department) { print "Department: $dept\n"; foreach my $name (keys %{$department{$dept}}) { my $salary = $department{$dept}{$name}; print " $name: $salary\n"; } } # 输出: # Department: IT # Alice: 5000 # Bob: 6000 # Department: Finance # Carol: 7000 # Dave: 5500 ``` ### 5. 使用 `map` 函数转换哈希 ```perl my @pairs = map { "$_ => $fruit{$_}" } keys %fruit; print join("\n", @pairs); # 输出: # apple => 3 # banana => 5 # orange => 2 ``` ### 关键注意事项 1. **遍历顺序**:默认无序,需用 `sort` 显式排序 ```perl foreach my $k (sort { $a cmp $b } keys %hash) # ASCII排序 ``` 2. **引用解包**:遍历哈希引用需用 `%$ref` ```perl my $href = \%fruit; while (my ($k,$v) = each %$href) { ... } ``` 3. **性能比较**: | 方法 | 内存占用 | 适用场景 | |------------|----------|-----------------------| | `each` | 低 | 大哈希遍历 | | `keys` | 中 | 需键名操作或排序 | | `values` | 中 | 仅需值 | | `map` | 高 | 转换操作 | 4. **修改警告**:遍历中删除键需使用 `delete` ```perl while (my ($k,$v) = each %hash) { delete $hash{$k} if $v < 0; # 安全删除 } ``` 实际选择取决于是否需要键名、排序要求及内存限制。日常推荐 `each` 或 `keys` 方法[^1][^5]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值