前言
继续今日学习~~
学会使用多维hash是我perl一级菜鸟进化成二级菜鸟的标志事件,目前等第二个标志事件已经等了一年半,还没有等到。因此我觉得还是把多维hash一些小事总结下好了。
正文
赋值
一维hash的赋值方式多种多样,而多维hash我一般就乖乖使用最基本的单点赋值方式,绝对不浪:
1. my %my_hash; 2. my $sig1 = "amod_bmod_awsize"; 3. my $sig2 = "bmod_amod_bresp"; 4. 5. $my_hash{$sig1}{name} = "amod_bmod_awsize"; 6. $my_hash{$sig1}{width} = 8; 7. $my_hash{$sig1}{link}{src} = "amod"; 8. $my_hash{$sig1}{link}{dst} = "bmod"; 9. 10. $my_hash{$sig2}{name} = "bmod_amod_bresp"; 11. $my_hash{$sig2}{width} = 2; 12. $my_hash{$sig2}{link}{src} = "bmod"; 13. $my_hash{$sig2}{link}{dst} = "amod"; 14. $my_hash{$sig2}{sel}{0} = 0; 15. $my_hash{$sig2}{sel}{2} = 2; 16. $my_hash{$sig2}{sel}{10} = 10;
当然了,多维hash一样可以跟一维一样用胖箭头赋值:
1. my %ascii_for_char = ( 2. 'digit' => { 3. '0' => 48, 4. '1' => 49, 5. }, 6. 'upper case' => { 7. 'A' => 65, 8. 'B' => 66, 9. }, 10. 'lower case' => { 11. 'a' => 97, 12. 'b' => 98, 13. }, 14. );
上面这个是我复制过来的,我自己还是喜欢把各个维度展开写,突出一个稳字。
多维hash的某一个key可能指向某一个值,也可能指向一个hash,例如上式中$my_hash{$sig2}指向一个多维hash,$my_hash{$sig2}{name}指向一个值。
而一个key是不能即指向一个值又指向一个其他的东西的,这个道理说起来太简单了,但是我之前就卯足了劲想这么用:
1. $my_hash{$sig} = "awsize"; 2. $my_hash{$sig}{src} = "a"; 3. $my_hash{$sig}{dst} = "b";
我当时觉得非常合理啊,我这个$sig指向一个信号名,然后下携两个子项分别是src和dst,天衣无缝非常完美的。但是呢,编译时候就在这报错,后来才想明白一个key不能有多个指向。
赋值时,$my_hash{$sig}{dst} = "b" 和 $my_hash{$sig}{"dst"} = "b"是一样的,当然%hash_A = ("key1" => value1, "key2" => value2) 和 %hash_A = (key1 => value1, key2 => value2) 也是一样的,keyx会自动被引号引起来。
打印
一维hash一般直接print %hash就够用了,而对于嵌套的多维数组呢,可以借助一个库来实现清晰的打印:
1. use Data::Dumper; 2. 3. my %my_hash; 4. 5. ........ 6. 7. print Dumper(\%my_hash);
打印效果不错,但还是有点美中不足(主要是递进看着难受):
所以本着有轮子还要自己造好看的轮子的原则,死心眼的写了这个函数:
1. sub display_hash{ 2. my $obj = shift @_; 3. my $tab_n = shift @_; 4. my $tab = ""; 5. my @re; 6. 7. $tab_n = 0 unless $tab_n; 8. 9. $tab = " " x $tab_n; 10. my %hash = %$obj; 11. for my $key(sort keys %hash){ 12. $str = $tab."$key"; 13. if(ref $hash{$key} eq "HASH"){ 14. #$str .= "\n"; 15. push(@re, $str); 16. @re = (@re, &display_hash(\%{$hash{$key}}, $tab_n+4)); 17. } else { 18. $str .= " => $hash{$key}"; 19. push(@re, $str); 20. } 21. } 22. return @re; 23. } 24. 25. sub display_list{ 26. my @list = @_; 27. for my $obj (@list){ 28. print "$obj\n"; 29. } 30. }
这样的话,打印hash就是这个效果:
&display_list(&display_hash(\%my_hash));
看着舒服了很多啊,而且可控性也高了很多,比如在里面加加颜色啥的都很方便;
使用sort时候注意,他的排序是根据首字符的,因此是0 10 2这样的顺序(即使key写成int(10)也不行),如果想通过key索引有先后顺序的value,不妨考虑使用1 11 111 1111这样做key?
数字的排序需要用$a <=> $b的写法,但是在遍历key时候应该怎么使用呢?我还没想清楚。
删除
同一维hash一样,删除一个key会将其所指向的内容全部删除:
1. delete $my_hash{bmod_amod_bresp}{width}; 2. delete $my_hash{"amod_bmod_awsize"}{name}; 3. 4. &display_list(&display_hash(\%my_hash));
遍历
这样就ok了,下层hash用%{}转一下:
1. for my $obj0 (sort keys %my_hash){ 2. for my $obj1(sort keys %{$my_hash{$obj0}}){ 3. print "$obj1, $my_hash{$obj0}{$obj1} \n"; 4. } 5. }
引用
正常的$obj = \%my_hash引用就可以了,解引用也可直接%hash = %$obj,或者不解直接用$obj -> {$sig1} -> {name}这样用应该也是没问题的,不过这中花哨的写法对我来说太难了,以下三种方式都可以:
1. my $hash = \%my_hash; 2. print "hello1, $hash->{amod_bmod_awsize}->{name} \n"; 3. print "hello2, $hash->{amod_bmod_awsize}{name} \n"; 4. print "hello3, ${$hash}{amod_bmod_awsize}{name} \n";
1. hello1, amod_bmod_awsize 2. hello2, amod_bmod_awsize 3. hello3, amod_bmod_awsize
初始化
多维哈希合并时候一样是这个语法(好像这些都是废话):
%hash = (%hash1, %hash2);
因此要初始化一个多维hash和之前一样:
%hash = ();
拷贝
hash进行=直接拷贝的话,是一种深层指针拷贝,看下这个代码:
1. delete $my_hash{$sig1}; # no use, to long 2. my $sig3 = "bmod_amod_buser"; 3. $my_hash{$sig3} = $my_hash{$sig2}; 4. 5. print "first, copy=====================\n"; 6. &display_list(&display_hash(\%my_hash)); 7. 8. print "\nfirst, delete====================\n"; 9. delete $my_hash{bmod_amod_bresp}{width}; 10. &display_list(&display_hash(\%my_hash));
打印结果:
1. first, copy===================== 2. bmod_amod_bresp 3. link 4. dst => amod 5. src => bmod 6. name => bmod_amod_bresp 7. sel 8. 0 => 0 9. 10 => 10 10. 2 => 2 11. width => 2 12. bmod_amod_buser 13. link 14. dst => amod 15. src => bmod 16. name => bmod_amod_bresp 17. sel 18. 0 => 0 19. 10 => 10 20. 2 => 2 21. width => 2 22. 23. first, delete==================== 24. bmod_amod_bresp 25. link 26. dst => amod 27. src => bmod 28. name => bmod_amod_bresp 29. sel 30. 0 => 0 31. 10 => 10 32. 2 => 2 33. bmod_amod_buser 34. link 35. dst => amod 36. src => bmod 37. name => bmod_amod_bresp 38. sel 39. 0 => 0 40. 10 => 10 41. 2 => 2
可以发现,拷贝是吧全部信息都拷过去了,但是$sig2 width被删除时,$sig3中对应的信息也被删除了。因此需要深度复制拷贝的话,请使用:
use Clone 'clone';