2011-06-21 16 views
3

まず、今後の投稿で何らかの用語が間違っていたら、これはまったく新しいものです。ハッシュされた配列にアクセスするより洗練された方法

バックグラウンドによっては、アーカイブされたネットワーク設定を特定の設定のためにチェックするスクリプトがあります。そのため、スクリプトはいくつかの検査を実行し、その検査の結果を配列に追加します。

例えば キーがあることと、すべてのチェックのための配列がハッシュに追加され実行されているすべてのチェック後

@internalsyslogerrorと呼ばれる配列に追加されるように構成されていることを確認のsyslogを作るためのチェック、装置名。すべてのコードは、次のコマンドで

に厳格な、使用の警告を使用有する

音符。

$results{$configs} = [@internalsyslogerror, @bordersyslogerror, 
@borderntperror, @borderntperror, @internalntperror, 
@bordertacacserror, @internaltacacserror, @enablepasswordchecks, 
@internalsnmpkeyserror, @timezoneerror, @configregistererror, 
@bannererror, @bootregistererror, @domainnameerror]; 

問題イム持つが、この情報を抽出する最もエレガントな方法は何かということです、私はスクリプトに新しいチェックを追加するために行う必要があり、変更の量を削減したいと思います。 現在、私は上記のコードに追加配列を追加し、それを処理するサブリファレンスに逆参照部分を追加する必要があります。

ここでは、現在、私は参照を外して配列に配置して電子メールで送信します。

foreach my $k (keys %results) { 
    push @results, "<b>$k</b><br>"; 
    if (defined $results{$k}[0]){ 
    push @results, "$results{$k}[0]"; 
    } 
    if (defined $results{$k}[1]){ 
    push @results, "$results{$k}[1]"; 
    } 
    if (defined $results{$k}[2]){ 
    push @results, "$results{$k}[2]"; 
    } 
    if (defined $results{$k}[3]){ 
    push @results, "$results{$k}[3]"; 
    } 
    if (defined $results{$k}[4]){ 
    push @results, "$results{$k}[4]"; 
    } 
    if (defined $results{$k}[5]){ 
    push @results, "$results{$k}[5]"; 
    } 
    if (defined $results{$k}[6]){ 
    push @results, "$results{$k}[6]"; 
    } 
    if (defined $results{$k}[7]){ 
    push @results, "$results{$k}[7]"; 
    } 
    if (defined $results{$k}[8]){ 
    push @results, "$results{$k}[8]"; 
    } 
    if (defined $results{$k}[9]){ 
    push @results, "$results{$k}[9]"; 
    } 
    if (defined $results{$k}[10]){ 
    push @results, "$results{$k}[10]"; 
    } 
    if (defined $results{$k}[11]){ 
    push @results, "$results{$k}[11]"; 
    } 
    if (defined $results{$k}[12]){ 
    push @results, "$results{$k}[12]"; 
    } 
    if (defined $results{$k}[13]){ 
    push @results, "$results{$k}[13]"; 
    } 
} 

質問は、私はイムは、上記のやって何をすべきか、どういうわけか "オンザフライ" のコードを生成することができますされ

おかげ

+2

IFSの膨大な数をちらっと見たときは、私はほとんど私が故に –

+0

@denis :-) thedailywtf.comを読んでいたと思いました助けを求める叫び:D – Steve

答えて

4

をこのスニペットが既存の動作を変更しないことを確認するのに十分なコードは見ていません。しかし、それは大丈夫です。そして、メンテナンス性が確実に向上します。

foreach my $k (keys %results) { 
    push @results, "<b>$k</b><br>"; 
    foreach my $index (0..$#{$results{$k}}) { 
     if (defined $results{$k}[$index]){ 
      push @results, "$results{$k}[$index]"; 
     } 
    } 
} 

上記のようにforeach/if構造全体が置き換えられます。

+0

これは驚くほどうまくいく、ありがとう。私は配列の数を得る方法があることを知っていたので、これを自分自身でやろうとしていましたが、うまく動作することができませんでした。ありがとう – Steve

3

は、forループを使用します。

for ($i = 0; $i < 14; $i++) { 
    ... 
} 
5
foreach my $k (keys %results) { 
    push @results, "<b>$k</b><br>"; 
    for my $result (@{$results{$k}) { 
     next if (!defined $result); 
     push @results, $result; 
    } 
} 

あるいは

foreach my $k (keys %results) { 
    push @results, "<b>$k</b><br>"; 
    push @results, grep { defined $_ } @{$results{$k}}; 
} 

編集:機能不全....このコードはあるようですが、私には見えます...最後のプッシュで

+0

+1 grepを使用して – Axeman

+0

私はこれらのソリューションの両方が好きです。私が投稿した後、私は「なぜインデックスを扱っているのですか?しかし、それはとても速く受け入れられました。私は変更を加えたくありませんでした。よくやった。 – DavidO

+0

ありがとう!いつもたくさんの方法があります... – hexcoder

2

をタイプミスを修正しました。私が間違っているなら、私を訂正してください。

$results{$configs} = [@internalsyslogerror, @bordersyslogerror, ... ]; 

これはスカラー値の一つの長い配列、アレイのない配列を作成します。この点を考慮してください。

C:\perl>perl -we "@a=qw(1 2 3 a); @g=(11,22,33,44); $b{key}=[@a,@g]; print qq(@{$b{key}},\n); print qq($b{key}[0]);" 
1 2 3 a 11 22 33 44, 
1 

をこれは明らか$b{key}@a@g、その$b{key}[0]両方のすべての値を含んでいることを示しているだけ$a[0]、すなわち、第一の配列の最初の値を指します。

$results{$config} = [\@internalsyslogerror, \@bordersyslogerror, ...]; 

唯一の方法I:あなたが特定のキーの下に、別の変数にログを収集することである、やっているように見えるものを行うために

、あなたは配列の参照を使用する必要があると思いますバグ/機能(意図または意図しない)を持っている場合は、各配列の最初の値は、そのカテゴリに関連するすべてのデータ、例えばが含まれていることにより、以前のコードで、あなたの現在のソリューションの作業をされて見ることができます:

$internalsyslogerror[0] = "device A not responding, shutting down.\ndevice A rebooted.\nyada yada\n ....";

これがカジノの場合あなたが配列の場合、システムがめちゃくちゃにされるのいずれかで2つの値を取得する必要があり、あなたはオフ・バイ持っているかどう

$results{$config} = [ $internalsyslogerror[0], $bordersyslogerror[0], ...]; 

しかし:E、その後、何をやっていることに相当しますレポートの最後に1つのエラーがあります。 pushに動的forループを使用していない限り、値は変わりませんが、依然として乱雑です。

はまた、未定義の値を除外することで、あなたの内部構造 - 唯一の順序に依存 - @resultsの最初の値が@internalsyslogerrorまたは@bordersyslogerrorから来る場合、あなたが知っているしないように、めちゃくちゃにされます。

結論:

あなたの現在のシステムがうまく機能に満足している場合は、他の人によって示唆されているように、単純にforループを使用します。絶対値ではなく動的値を使用します。ただし、内部構造を保持したい場合は

# Solution by FMc 
for my $k (keys %results) { 
    push @results, "<b>$k</b><br>"; 
    push @results, grep { defined $results{$k}[$_] } 0 .. $#results{$k}; 
} 

は、あなたが未定義の値を除外することはできません、あなたがない限り、1にすべての異なるアレイに参加することはできません:私は(少し変更された)FMCのソリューションが好きデータはすでに最初の配列値の文字列で結合されています。したがって:

$results{$config} = [ \@array1, \@array2, ...]; 

.... 

for my $key (keys %results) { 
    push @results, "<b>$key</b><br>"; 
    my $i=0; 
    for my $ref (@{$results{$key}]) { 
     push @results, "Array $i:\n<br>" . (defined @$ref ? "@$ref" : ""); 
     $i++; 
    } 
} 

出力の書式設定も微調整できます。文字列結合の代わりに、例えば。 "@array"の場合は、明示的に参加することができます:join("<br>\n", @array)

+0

コメントのおかげで、あなたは正しいですが、私のコードの大部分で、ちょっとハッキリしています...各配列がデバイスでハッシュに送られた後名前をキーにすると、配列はクリアされ、次のデバイスは新しい配列を生成します。ありがとう – Steve

+0

@Steve制限付きレキシカルスコープ内で配列を使用すると、そのアドレスはループ毎に再作成されるので(手動で消去する必要はありません)、データを破損することなく参照を追加することができます。例えば。'for $ key(@yada){my @array = something($ key);私の@ array2 = something2($キー); $ hash {$ key} = [\ @ array、\ @ array2]; } 'うまく動作します。 – TLP

+0

ああ、ちょうど何を探しているのですか。悪いテストそのうちに – Steve

1

キーで何もしていない場合、これは等価です:

@results = map { "$_" } grep {; defined } map { @$_ } values %results; 
関連する問題