2010-12-02 117 views
1

在Perl中的哈希存在的對,我有類似以下Perl中,檢查是否在哈希

my %HoH 
    for my $i (1..10) { 
     $HoH{$a}{$b} = $i; 
    } 

$一個的迴路形成哈希散列和$ b是做有當一些值的變量HoH得到填充。在創建HoH之後,我如何檢查HoH中是否存在特定的對($ c,$ d)?以下不工作

if (defined $HoH{$c}{$d}) {...} 

,因爲如果$ C不可可西里已經存在,它會爲沒有價值的關鍵創建。

+0

不完全:如果散列不包含`$ c`的值,它將被創建爲一個(新的,匿名)散列的引用,因爲這就是它的使用方式。這就是所謂的「autovivification」。 – 2010-12-02 16:34:12

回答

3
use Data::Dumper; 

my %HoH; 

$HoH{A}{B} = 1; 

if(exists $HoH{C} && exists $HoH{C}{D}) { 
    print "exists\n"; 
} 

print Dumper(\%HoH); 

if(exists $HoH{C}{D}) { 
    print "exists\n"; 
} 

print Dumper(\%HoH); 

輸出:

$VAR1 = { 
      'A' => { 
        'B' => 1 
       } 
     }; 
$VAR1 = { 
      'A' => { 
        'B' => 1 
       }, 
      'C' => {} 
     }; 

Autovivification導致鍵被創建。 「存在」在我的第二個例子中顯示了這一點,所以第一個例子單獨檢查兩個鍵。

+0

你知道,你並不需要使用繁瑣的「存在」。 – tchrist 2010-12-02 15:53:23

0

您必須使用exists功能

存在EXPR

鑑於指定哈希的 元素的表達,如果在哈希 指定元素曾經 被初始化返回true ,即使 對應的值未定義。

注意,EXPR可以是隻要最終 操作是一個散列或陣列鍵 查找或子程序名任意 複雜:

  1. 如果(存在$ REF - > {A} - > {B} - > {$鍵}){}
  2. 如果(存在$散列{A} {B} {$鍵}){}
+0

不起作用,我想是因爲我沒有試圖查看是否存在$ key,但是是否定義了$ hash {A} {B} ...無論如何感謝! – 2010-12-02 15:43:04

+2

`存在`不會破壞autovivification。 – 2010-12-02 15:53:05

+0

「存在」既不是在這裏實現解決方案所必需也不足夠的措施。 – tchrist 2010-12-02 19:32:23

4

寫作

if (defined $HoH{$c}{$d}) {...} 

將「工作」之多,因而它會告訴你$HoH{$c}{$d}是否有一個確定的值。問題是,如果$HoH{$c}尚不存在,它將被創建(使用適當的值),以便可以測試$HoH{$c}{$d}。這個過程被稱爲「autovivification」。設定數值時很方便,例如

my %hoh; 
$hoh{a}{b} = 1; # Don't need to set '$hoh{a} = {}' first 

但在檢索可能不存在的值時不方便。我希望Perl足夠聰明,只能對用作左值和短路的表達式進行自動版本化,以便爲rvalues返回undef,但是,唉,它並不那麼神奇。 autovivification編譯指示(CPAN上提供)添加了執行此操作的功能。

爲了避免自動激活,你需要首先測試的中間值:

if (exists $HoH{$c} && defined $HoH{$c}{$d}) { 
    ... 
} 
2

幾種方法:

if ($HoH{$c} && defined $HoH{$c}{$d}) {...} 

if (defined ${ $HoH{$c} || {} }{$d}) {...} 

no autovivification; 
if (defined $HoH{$c}{$d}) {...} 

use Data::Diver; 
if (defined Data::Diver::Dive(\%HoH, $c, $d)) {...} 
0

我的看法:

use List::Util qw<first>; 
use Params::Util qw<_HASH>; 

sub exists_deep (\[%$]@) { 
    my $ref = shift; 
    return unless my $h = _HASH($ref) // _HASH($$ref) 
       and defined(my $last_key = pop) 
       ; 
    # Note that this *must* be a hash ref, for anything else to make sense. 
    return if first { !($h = _HASH($h->{ $_ })) } @_; 
    return exists $h->{ $last_key }; 
} 

你也這樣做遞歸。你也可以創建一個下降結構,允許中間甚至終端arrayref只需要一些額外的編碼。