前言
雜湊 (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"}
由鍵取值。