each

2013-08-24 01:34

5.4 each
就像在陣列當中,你可以使用foreach這樣的迴圈來找到陣列中的每一個值,當然我們也經常需要在雜湊中進行類似的工作,我們希望可以在雜湊中能一次取 出所有的鍵,值。所以你必須仰賴類似foreach的工具來幫助你,那就是each函數。例如你可以利用下面的寫法讀出剛剛我們所建立起來的雜湊:

 


while (my ($key, $value) = each (%hash)) {  	
      # 取出雜湊中的每一對鍵值,並且分別放入$key, $value
      print "$key => $value\n";
}


很明顯的,每次each函數都會送回了一個包含兩個值的串列,其中這兩個值分別是一個雜湊鍵跟相對應的值。因此我們把取回的串列指定給$key 和$value兩個變數,接著印出結果,就可以看到一對一對的鍵值了。而當傳回空陣列時,while判斷就會變成偽值,while迴圈也就結束了。利用這 樣的函式對我們有很大的幫助,如果我們想要整理一個雜湊的內容,我們可以在完全不知道雜湊中有什麼內容的狀況下開始進行處理。使用each函數在處理雜湊 時是讓事情顯得容易許多,可是有時候還是有點不方便的地方,舉例來說:如果我有一個包含著主機ip跟主機名稱的雜湊,雖然我不知道雜湊裡面到底有多少資 料,可是我卻希望能找出所有的雜湊鍵值,然後取出以192開始的ip位址。這時候如果使用each來作,那就必須先把所有的鍵值取出,然後再一一進行比 對,所以也許程式就像這樣:
 


my %hash = (
            '168.1.2.1' => 'verdi',
            '192.1.2.2' => 'wagner',
            '168.1.2.3' => 'beethoven',
            );  				# 定義主機跟ip 的對應
my @hostname;
while (my ($key, $value) = each (%hash)) {
    if ($key =~ /^192/) {  		# 要找出ip以192開頭的部份
        push @hostname, $value;  		# 找到之後放入新的陣列中
    }
}

print @hostname;


很顯然,這樣的寫法確實可以讓程式正確的找出我們要的結果,不過我們總是還會繼續思考可以有更乾淨俐落的寫法,畢竟使用Perl的程式設計師都不太喜歡拉拉雜雜的程式。所以有甚麼方法可以讓過濾出需要的鍵值可以顯得方便些呢?

5.5 keys跟values
如果我們可以用簡單的方式一次取得雜湊的所有鍵(keys),那麼要進行過去的過程就非常容易,而我們所需要的就是過濾後留下來的鍵,跟他們的相對值。當 然,有某些時候,你可能只想要拿到雜湊中的所有值,這時候你就不需要擔心他們是屬於什麼鍵的相關。為了因應這樣的需求,有兩個函數可以滿足我們,他們分別 是keys跟values。很顯然的,這兩個函數所作的工作就是取出雜湊的鍵跟值。和使用 each相當不同的是:你可以只單讀取出所有的鍵,或所有的值,而不需要一次全部取出。
例如我們可以用這樣來把雜湊鍵放在同一個陣列中:

 


my @keys = keys(%hash);


如果你希望取出所有的值,那麼不妨這樣寫:
 


my @values = values(%hash);


當然,你可以用他來完成each的工作,就像這樣:
 


my @keys = keys(%hash);
for (@keys) {
    print "$_ => $hash{$_}\n";
}

其實跟這麼寫是一樣的效果:

while (my ($key, $value) = each(%hash)) {
      print "$key => $value\n";
}


不過你顯然會發現,有時候用keys/values比較簡單,有時候用each比較方便,當然,至於要使用何者是完全取決於你所想要得出的結果,或者你認為最省力,簡潔,或是效率比較好的寫法。

在雜湊中使用keys/values這兩個函數都傳回串列,因此我們可以把我們所得到的串列輕易的放入陣列,接下來再以陣列的方式進行運算。這樣的方便之處在於我們可以有很多可供利用的陣列函數,所以我們可以把剛剛的那個例子改寫成這樣:

 


my %hash = (
            '168.1.2.1' => 'verdi',
            '192.1.2.2' => 'wagner',
            '168.1.2.3' => 'beethoven',
            );

my @keys =  map { $hash{$_} }
            grep { (m/^192/) } keys(%hash);

print @keys;


這樣的寫法比起之前的方式看起來是不是乾淨許多了呢?我們來看看最關鍵的一行,結果到底怎麼產生的:我們先用keys函數取出雜湊中的所有鍵,就如我們所 說的,這個函數傳回一個串列。然後我們對所得到的串列進行過濾,利用grep取出串列中以192開頭的ip子串列,最後利用map一一比對得出雜湊中以對 應這些ip的主機名稱。