使用雜湊 (Hash) 或關連式陣列 (Associative Array)

    前言

    雜湊 (hash) 或關連式陣列 (associative array) 是以鍵/值對為儲存單位的非線性容器,在 Perl 中相當實用。

    建立雜湊

    以下程式建立一個空雜湊:

    my %h = ();
    

    以下程式建立一個有儲存鍵/值對的雜湊:

    my %h = (
        one => "eins",
        two => "zwei",
        three => "drei",
    );
    

    也可以先建立空雜湊後再逐一填入鍵/值對:

    my %h = ();
    
    $h{one} = "eins";
    $h{two} = "zwei";
    $h{three} = "drei";
    

    如果雜湊的鍵/值對都是字串,其實有更簡便的建立方式:

    my %h = qw(
        one eins
        two zwei
        three drei
    );
    

    因為 qw 會建立一個字串串列,而字串串列會自動成對加入雜湊。從另一個觀點來看,=> 其實只是逗號的另一個寫法,故 qw 的寫法也通用。

    存取雜湊的值

    雜湊以鍵為索引,藉由鍵取值。見下例:

    my %h = (
        one => "eins",
        two => "zwei",
        three => "drei",
    );
    
    $h{one} eq "eins" or die "Wrong value";
    $h{two} eq "zwei" or die "Wrong value";
    $h{three} eq "drei" or die "Wrong value";
    

    在取值時,取回的是純量,故要寫成 $h{one},一開始易寫錯,需注意。

    由於雜湊內部的演算法,取索引運算是單向的。使用雜湊時,只能以鍵取值,不能以值取鍵;此外,鍵不能重覆而值可以。

    確認鍵值對是否存在

    使用 exists() 函式可確認鍵值對存在與否,如下例:

    my %h = (
        one => "eins",
        two => "zwei",
        three => "drei",
    );
    
    exists($h{one}) or die "It should exist";
    !exists($h{four}) or die "It should not exist";
    

    exists()defined() 兩者的意義是不同的。前者會確認鍵/值對是否存在,而後者會確認值本身是否有定義。

    移除鍵值對

    使用 delete() 函式可刪除鍵值對。參考以下程式碼:

    my %h = (
        one => "eins",
        two => "zwei",
        three => "drei",
    );
    
    exists($h{one}) or die "It should exist";
    
    delete $h{one};
    !exists($h{one}) or die "It should not exist";
    

    將鍵值對設為未定義不會刪除該鍵值對。參考以下程式碼:

    my %h = (
        one => "eins",
        two => "zwei",
        three => "drei",
    );
    
    exists($h{one}) or die "It should exist";
    
    $h{one} = undef;
    exists($h{one}) or die "It should exist";
    

    請注意兩者的差別。

    走訪雜湊

    可透過鍵來走訪雜湊,這時候會搭配 keys 函式。參考下例:

    my %h = (
        one => "eins",
        two => "zwei",
        three => "drei",
    );
    
    for my $k (keys %h) {
        print "$k: $h{$k}\n";
    }
    

    keys 函式會以串列的形式回傳雜湊的鍵,故可以用 for 走訪。

    如果不需要鍵,也可以直接走訪值,這時候會搭配 values 函式。參考下例:

    my %h = (
        one => "eins",
        two => "zwei",
        three => "drei",
    );
    
    for my $v (values %h) {
        print "$v\n";
    }
    

    values 會以串列的形式回傳雜湊的值,故可以用 for 走訪。

    如果同時需要鍵/值對,也可搭配 each 函式來走訪雜湊。參考下例:

    my %h = (
        one => "eins",
        two => "zwei",
        three => "drei",
    );
    
    while (my ($k, $v) = each %h) {
        print "$k: $v\n";
    }
    

    注意這時會用 while 而非 for 來走訪。

    有序雜湊 (Ordered Hash)

    如果多執行幾次程式,會發現每次走訪雜湊的順序相異,因為雜湊在儲存鍵/值對時不會儲存其順序。Perl 沒有內建的有序雜湊,如果要保存雜湊的儲存順序,要將鍵的順序另存在一個陣列中,藉由設置鍵陣列的順序來控制取出值的順序。可見下例:

    my %h = (
        one => "eins",
        two => "zwei",
        three => "drei",
    );
    
    my @order = ();
    push @order, "one", "two", "three";
    
    for my $k (@order) {
        print "$k: $h{$k}\n";
    }
    

    模擬多維陣列

    藉由操作雜湊的鍵,可以用雜湊來模擬多維陣列。見下例:

    my %mtx = ();
    
    for (my $i = 0; $i < 3; $i++) {
        for (my $j = 0; $j < 3; $j++) {
            $mtx{$i, $j} = ($i+1) * ($j+1);   
        }
        
    }
    
    $mtx{1, 2} == 6 or die "Wrong value";
    

    這個程式能成立的關鍵在於 $mtx{$i, $j} 中會將 $i, $j 自動合併成一個字串,看起來就很像多維陣列。由於 Perl 5 後支援參考 (reference),現在比較少用這個技巧。如果陣列比較稀疏或是其索引為字串,仍可用這個技巧來建立多維陣列。

    取出多個雜湊值

    有時候我們會看到 @hash{$a, $b, $c} 的寫法,讀者可能會感到疑惑。@hash{$a, $b, $c} 代表我們得到的值是一個陣列,該陣列的值由原本的 %hash 中取得。見下例:

    my %h = (
        one => "eins",
        two => "zwei",
        three => "drei",
    );
    
    for my $e (@h{"one", "two", "three"}) {
        print $e, "\n";
    }
    

    在本例中,我們對 %h 取值,由於一次要取多個值,故寫成 @h,但仍由原雜湊取值,故寫成 @h{"one", "two", "three"} 由鍵取值。

    【分享本文】
    Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Yahoo
    【追蹤本站】
    Facebook Facebook Twitter