2011-07-31 9 views
14

私はこのようになり、ネストされたハッシュテーブルを持っています。このデータ構造を持つPerlの「存在する」データ構造体の値を変更できますか?

my %myhash = (
    "val1" => { 
     "A/B.c" => { 
      "funct1" => 1 
     } 
    }, 
    "val2" => { 
     "C/D.c" => { 
      "funct2" => 1 
     } 
    } 
) 

私の目的は、特定のハッシュテーブルが存在するかどうかに基づいて異なる値を生成することです。たとえば、

sub mysub 
{ 
    my $val = shift; 
    my $file = shift; 
    my $funct = shift; 

    if (exists $myhash{$val}{$file}{$funct}) { 
     return "return1"; 
    } 
    if (exists $myhash{$val}{$file}) { 
     return "return2"; 
    } 
    return "return3"; 
} 

私が直面している動作は次のとおりです。私は時間のインスタンスを持っています my $ val = "val1"; my $ file = "C/D.c"; my $ funct = "funct3";

この時点では、戻り値は「return2」になります。これらは、Perlデバッガと私の観察です:最初のMYSUBで

  • "であれば" 印刷のp $のproxToBugs { "val1と"}、{ "C/D.C"}で

    1. ブレーク==>空白行を返します。はい。続行し、この「if」をスキップします。
    2. 続行と第二の "if" MYSUBで
    3. プリントPの$のproxToBugs { "val1と"}、{ "C/D.C"} ==>で破る "(0X ...)HASH" を返します。 WTFの瞬間関数は "return2"を返します。

    これは、最初にデータ構造を変更した場合、2番目のifを渡すことができない場合に実行することを示しています。実行している関数は上記の関数と同じです。これはちょうど消毒されています。誰でも私に説明がありますか? :)

  • 答えて

    21

    はい。これはautovivificationのためです。主に深くネストされた配列やハッシュは、その存在は、介在するもの[自動活性化配列やハッシュ]意志[春にテストされたという理由だけで存在するようにしませんが、

    existsドキュメントの一番下を参照してください。存在]。 $ ref - > {"A"}と$ ref - > {"A"} - > {"B"}は、上記の$ key要素の存在テストのために存在します。これは、矢印演算子が使用されているどこにでも起こる...

    "... ...上記の$重要な要素のためのテスト" とはどこに:

    if (exists $ref->{A}->{B}->{$key}) { } 
    if (exists $hash{A}{B}{$key})  { } # same idea, implicit arrow 
    

    コーディングハッピー。

    +2

    確認済み...まだPerlで学ぶことがたくさんあります。このことは30分以上にわたってナッツを運転していました。ありがとう! – danns87

    8

    あなたがautovivificationをオフにしたい場合は、辞書的にautovivificationプラグマでそれを行うことができます。

    { 
    no autovivification; 
    
    if(exists $hash{A}{B}{$key}) { ... } 
    } 
    

    私はTurn off autovivification when you don’t want itとしてThe Effective Perlerでこれについての詳細を書きました。

    +0

    非常に気の利いた。これが存在するかどうかはわかりませんでした。 –

    9

    pstが正しく指摘しているとおり、これは自動化された機能です。それを避けるために少なくとも2つの方法があります。第一(及び私の経験の中で最も一般的には)各レベルでテストすることである。

    if (
        exists $h{a}  and 
        exists $h{a}{b} and 
        exists $h{a}{b}{c} 
    ) { 
        ... 
    } 
    

    andの短絡の性質は、以前のレベルがない場合に実行されないようにexistsに第二及び第三の呼び出しを引き起こします存在する。

    より最近の溶液は(CPANから入手可能)autovivificationプラグマである:

    #!/usr/bin/perl 
    
    use strict; 
    use warnings; 
    
    use Data::Dumper; 
    
    $Data::Dumper::Useqq = 1; 
    
    { 
        my %h; 
    
        if (exists $h{a}{b}{c}) { 
         print "impossible, it is empty\n"; 
        } 
    
        print Dumper \%h; 
    } 
    
    { 
        no autovivification; 
    
        my %h; 
    
        if (exists $h{a}{b}{c}) { 
         print "impossible, it is empty\n"; 
        } 
    
        print Dumper \%h; 
    } 
    

    ysthコメントに言及第三の方法は、(最初​​の例のように)コアであることの利点を有していませんのexists関数呼び出しを繰り返す。

    if (exists ${ ${ $h{a} || {} }{b} || {} }{c}) { 
        ... 
    } 
    

    それはautovivificationを取るためにハッシュリファレンスと存在していない任意のレベルを交換することによって動作します。しかし、私はそれがとても読みやすさを犠牲にしないと信じています。これらのハッシュリファレンスは、ifステートメントの実行が終了すると破棄されます。ここでも、短絡ロジックの価値がわかります。

    もちろん、これらの3つの方法はすべて、ハッシュが保持すると予想されるデータについて仮定しています。オブジェクトを扱う方法によってはrefまたはreftypeへの呼び出しが含まれます。 )ハッシュインデックス演算子をオーバーロードアカウントのクラスになりますが、私はその名前を覚えていないことができます。myExists($ref,"a","b","c")のようなものが存在する場合は、コメントで

    if (
        exists $h{a}   and 
        ref $h{a} eq ref {} and 
        exists $h{a}   and 
        ref $h{a}{b} eq ref {} and 
        exists $h{a}{b}{c} 
    ) { 
        ... 
    } 
    

    、PSTは尋ねました。私は、CPANにモジュールがあり、そのようなことは確かですが、私はそれを認識していません。私にとってそれが有用であることを知るには多すぎるケースがありますが、簡単な実装は次のようになります。

    #!/usr/bin/perl 
    
    use strict; 
    use warnings; 
    
    use Data::Dumper; 
    
    sub safe_exists { 
        my ($ref, @keys) = @_; 
    
        for my $k (@keys) { 
         return 0 unless ref $ref eq ref {} and exists $ref->{$k}; 
         $ref = $ref->{$k}; 
        } 
        return 1; 
    } 
    
    my %h = (
        a => { 
         b => { 
          c => 5, 
         }, 
        }, 
    ); 
    
    unless (safe_exists \%h, qw/x y z/) { 
        print "x/y/z doesn't exist\n"; 
    } 
    
    unless (safe_exists \%h, qw/a b c d/) { 
        print "a/b/c/d doesn't exist\n"; 
    } 
    
    if (safe_exists \%h, qw/a b c/) { 
        print "a/b/c does exist\n"; 
    } 
    
    print Dumper \%h; 
    
    +1

    第3の方法: 'exists $ {$ {$ val} || {}} {$ file} || {}} {$ funct} ' – ysth

    +0

    ' myExists($ ref、 "a"、 "b"、 "c")のやり方は? :) –

    関連する問題