2010年8月22日 星期日

[Perl 學習手冊] CH06 : 雜湊

前言 : 
這一張我們將看到 Perl 的特色之一 : 雜湊 (Hash). 它使 Perl 擠身偉大程式語言之一. 雜湊是一種資料結構, 和陣列相同之處 : 可以用來包含任意個數的值, 並能讓你隨心所欲的取用這些值 ; 和陣列不同之處 : 陣列是以數字來編索引, 而雜湊是用名稱來找尋相應的值. 換句話說, 雜湊的索引值 (index) - 此處稱為鍵 (key) - 並不是數值, 而是互相不同的任意字串. 
首先這些鍵是字串 (string), 因此我們將存取名為 wilma 的雜湊元素而不是像陣列那樣存取編號為3 的元素. 並且雜湊只能有一個名叫 wilma 的元素就像陣列只能有一個編號為3 的元素一樣. 

存取雜湊元素 : 
要存取雜湊元素, 可以使用以下的語法 : 
$hash{$some_key} 

這與存取陣列的做法類似, 但是我們會在索引值 (雜湊鍵) 旁邊使用大括號, 而不是方括號. 另外鍵運算式現在是字串而不是數值 : 

$family_name{"lee"} = "John";
$family_name{"wang"} = "Ken";

若要參用整份雜湊, 請用百分比 (%) 開頭, 因此前面的雜湊可以寫成 %family_name. 為了方便起見, 雜湊可以被轉成串列, 反之亦然. 對雜湊賦值等於是在串列語境中賦值, 其中串列是由 "鍵/值" 所組成 : 
  1. $some_hash = ("john"30"Peter"23"Mary"1819"Others\n");  
  2. @any_array = %some_hash;  #雜湊的值(在串列語境) 則是簡單的 "鍵/值" 串列.  
上面第二行我們稱之為 "展開" 雜湊, 也就是將之轉換成 "鍵/值" 串列, 然而這些 "鍵/值" 並不會保持原先串列的順序. 

- 雜湊的賦值運算 
雖然很少這樣做, 但是你可以使用一般賦值語法來賦製雜湊 : 
%new_hash = %old_hash; 

對Perl 來說, 上面都會轉換成串列的操作. 也就是將 %old_hash 轉成串列 (鍵/值) 後, 在存放到 %new_hash 代表的 "鍵/值" 串列中. 同樣的如果我們想要建立一個反序的雜湊, 我們可以這樣做 : 
%inverse_hash = reverse %any_hash; 

原先的 %any_hash 的 "鍵/值" 串列如果是 (key1, value1, key2, value2,...) 透過 reverse 會被轉成 (valuen, keyn, ... , value1, key1) 這個樣子, 現在鍵位於值原先的位置, 而值位於鍵的位置. 當他回存 %inverse_hash 時, 我們便能以原本的 "值" (在%any_hash是值, 現在是鍵) 在 %inverse_hash 取的對應的 "鍵" (現在是"值"). 
但是前面的操作必須再原先雜湊中的值, 互相不重複 (鍵值不能 duplicate) 才能作用. 而在 Perl 的雜湊中, 後面出現的鍵值會覆蓋前面已經存在的鍵值. 故雖然上面 %inverse_hash 可以生成, 但可能已經不是原先預期的結果了. 

- 大箭號 (=>) 
在使用串列對雜湊進行賦值時, 在判斷鍵值時並不是很方便. 若 Perl 能讓我們將此類串列的鍵與值成對組合, 將方便我們進行維護. 所以大箭號派上用場了. 對 Perl 而言, 大箭號只是逗號(,) 的另一種寫法. 也就是說依照 Perl 的文法, 在任何需要逗號的地方, 都可以用大箭號來代替 ; 兩者對 Perl 式相同的. 所以使用串列對雜湊賦值可以 : 
  1. my %last_name = (  
  2.     "lee" => "john",  
  3.     "wang" => "ken",  
  4.     "lin" => "Mary",   
  5. );  
請注意這裡的串列結尾有一個額外的逗號 ; 而這種寫法無傷大雅而且相當方便 ; 假如我們需要新增額外的人名到雜湊中, 只要確認每一列都有一組 "鍵/值" 對和結尾的逗號就可以了. 

雜湊處理函式 : 
Perl 有些好用的函式可以用來處理雜湊 : 
- keys 和 values 函式 
keys 函式會傳回目前雜湊中所有的鍵 ; 而 values 函式所傳回的則是相應的每個值. 假如雜湊裡沒有任何元素, 這兩個元素都會傳回空串列 : 
  1. my %my_hash = ("a" => 1"b "=> 2"c" => 3);  
  2. my @k = keys %my_hash;  
  3. my @v = values %my_hash;  
所以 @k 會包含 "a", "b", "c" 而 @v 則會包含 1, 2, 3 - 但不一定會照這個順序. 但是無論鍵的順序為何, 值的順序都會跟它一樣 : 假如 "b" 是最後一個鍵, 則 2 就會是最後一個值. 只要你再取的鍵與取得值這兩個動作之前, 沒有更對到雜湊, 順序就會保持. 假如你要新增元素到雜湊中, Perl 會保留重新排列的權利以保持存取的速度. 在純量語境下, 這兩個函式都會傳回雜湊元素的個數. 
my $count = keys %my_hash; # 傳回 3, 表示三組鍵/值 對. 

- each 函式 
假如你想對整份雜湊進行迭代 (iterate) , 使用 each 函式 是常見的做法. 此函式會回傳函有兩個元素的串列, 也就是 鍵/值對. 之後每次對同樣的雜湊呼叫 each 時, 它會傳回下一組 鍵/值 對, 直到所有的元素都被存取過. 在所有的元素都被存取過後, 再次呼叫將會回傳空串列. 
實務上唯一適合使用 each 的地方是在 while 迴圈之中, 範例代碼如下 : 
  1. my %my_hash = ("a" => 1"b "=> 2"c" => 3);  
  2. while(($key, $value) = each(%my_hash)) {  
  3.     print "key=$key, value=$value\n";  
  4. }  
當有鍵/值對從 each 函式回傳時, 在串列賦值運算回傳的將會是來源串列元素的個數 (這裡是2), 因此 while 迴圈會繼續進行一直到所有 鍵/值 都走訪過後, 最後一次的串列賦值的 $key 與 $value 都會得到 undef. 所以串列賦值運算將會回傳 0. 因此結束了 while 迴圈. 這裡說明當你想要對雜湊進行簡單排序, 事實上你可以從鍵值著手 : 
  1. my %my_hash = ("a" => 1"b "=> 2"c" => 3);  
  2. foreach(sort keys %my_hash) {  # 對鍵的串列進行排序  
  3.     my $value = $my_hash{$_};  
  4.     print "key=$_, value=$value\n";  
  5. }  
- exists 函式 
要檢視某個鍵是否存在雜湊中, 可以使用 exists 函式. 假如雜湊中有這個鍵, 它就會回傳真值 : 
  1. if(exists $my_hash{"e"}) {  
  2.     print "key(e) exist!\n";      
  3. }  
也就是說, 若(且唯若) "e" 出現在 keys %my_hash 所傳回的鍵串列中, exists $my_hash{"e"} 才會傳回真值. 

- delete 函式 
delete 函式將會從串列移除你所指定的鍵(與對應的值). 假如沒有對應的鍵, 就會直接結束而不會有任何警告或錯誤訊息. 
  1. my $person = "john";  
  2. delete $books{$person};  # 刪除 "john" 這個鍵  
- 雜湊 %ENV 
如同任何其他程式, 你的Perl 程式也是運作在某個環境之中, 因此你的程式可以取得環境相關的資訊. Perl 將此資訊存在雜湊 %ENV 中, 例如你可以檢查雜湊 %ENV 的 PATH 鍵, 範例如下 : 
print "PATH is $ENV{PATH}\n"; 

補充說明 : 
* Tutorialspoint > Perl Hash Variables : 
Hashes are an advanced form of array. One of the limitations of an array is that the information contained within it can be difficult to get to. For example, imagine that you have a list of people and their ages.
The hash solves this problem very neatly by allowing us to access that @ages array not by an index, but by a scalar key. For example to use age of different people we can use thier names as key to define a hash.

* Perl 學習手扎 > 雜湊 (Hash) :

沒有留言:

張貼留言

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...