2011-06-21 35 views
3

首先,appologies,如果我在即將發佈的帖子上得到任何術語錯誤,這對我來說仍然是非常新的。訪問哈希數組的更優雅的方式

一些背景知識,我有一個腳本,檢查我們存檔的網絡配置爲一組特定的設置。因此,該腳本運行多次檢查,並將結果添加到該檢查的數組中。

例如 一個檢查,以確保系統日誌被配置被添加到稱爲@internalsyslogerror

所有的檢查之後的陣列已經運行時,用於所有的檢查陣列被添加到散列,用鍵爲設備名稱。

記下所有代碼使用嚴格的,使用警告

用下面的命令;

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

遇到的問題IM是什麼,是提取信息的最優雅的方式,我想,以減少爲了增加一個新的支票給腳本修改我不得不作出的量。 目前我將不得不添加額外的數組到上面的代碼,然後將解引用部分添加到處理它的子。

這裏是目前我所做的解除參考和輸出到一個數組,然後通過電子郵件發送。

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]"; 
    } 
} 

的問題是,我可以做什麼IM上面做,但不知何故, 「對飛」 生成代碼

感謝

+2

一旦在IFS的龐大的數字一眼,我差點以爲我是在閱讀,因此:-) thedailywtf.com –

+0

@denis呼救: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, ...]; 

我的唯一方法可以看到當前解決方案的工作,就是如果你有一個bug /功能(有意或無意)早些時候在你的代碼,其中每個陣列中的第一個值包含了所有有關該類別的數據,例如:

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

如果這是CAS如果你曾經獲得兩個值的陣列,那麼你的系統將被搞砸了的一個,你將有一個關閉的情況

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

:e,然後你在做什麼是相當於在報告結尾處出現一個錯誤。除非你使用動態for循環來獲取push的值,但它仍然會是凌亂的。

而且,通過排除未定義值,你的內部結構 - 這僅取決於順序 - 將被搞砸了,讓你不會知道,如果在@results第一值來自@internalsyslogerror@bordersyslogerror

結論:

如果你很高興與你當前的系統運作良好,簡單地利用他人for循環的建議。使用動態值而不是絕對值。我喜歡FMC解決方案(輕微改變):

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

但是,如果你想保留的內部結構,就不能排除未定義的值,你不能所有不同的陣列連接成一個,除非數據已經在第一個數組值中加入了字符串。所以:

$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如果你在一個受限制的詞法範圍內使用數組,它們的地址將在每個循環中重新創建(所以你不必手動清除它們),並且可以在不破壞數據的情況下添加一個引用。例如。對於$ key(@yada){my @array = something($ key); my @ array2 = something2($ key); $ hash {$ key} = [\ @array,\ @ array2]; }'會工作得很好。 – TLP

+0

啊,多數民衆贊成在什麼即時尋找..虐待測試,謝謝 – Steve

1

如果你未向密鑰做任何事情,這相當於:

@results = map { "$_" } grep {; defined } map { @$_ } values %results;