1.ハッシュへ値を代入
ハッシュ変数は、配列のインデックスが文字列となったもので、このインデックスを『キー』と呼びます。ハッシュの場合は要素の値がキーによって管理されます。
ハッシュの宣言
ハッシュを宣言するときは変数名の前にパーセント( % )を付けます。
%hash;
ハッシュへ値を代入
配列では、[ ] でインデックスを囲みましたが、ハッシュは、 { }でキーを囲みます。例えば社員の名前とメールアドレスを管理する場合、次のような方法でハッシュを使った管理ができます。
$hash{'Akai'} = 'akai@domain.com'; $hash{'Ishikawa'} = 'ishi@domain.com'; $hash{'Ueda'} = 'ueda@domain.com';
複数の値を一度にハッシュへ代入するには、キー、値の順番で記述します。
%hash = ('Akai', 'akai@domain.com', 'Ishikawa', 'ishi@domain.com');
=> 演算子を使うと読みやすくなります。
%hash = ( "Akai" => 'akai@domain.com', "ihikawa" => 'ishi@domain.com', );
また、ハッシュ変数をハッシュ変数に直接代入することによって、ハッシュをコピーすることもできます。
%new = %old; # %oldの内容を%newにコピーする
2.ハッシュの値を参照
ハッシュも配列と同様に、ハッシュ用の参照書式があり、さらに参照用の関数も用意されています。
- キーを使ってハッシュの要素を参照
- keys 関数
- values 関数
- ハッシュのすべての要素を処理
- sort関数でキーをソート
- each 関数
- キーに対応する値があるかチェック
- ハッシュをリストコンテキストで評価
- ハッシュの要素数を調べる
- ハッシュの消去
- ハッシュの操作関数
キーを使ってハッシュの要素を参照
ハッシュの各要素を参照するには、キーを { } で囲んで指定します。
%hash = ('Akai', 'akai@domain.com', 'Ishikawa', 'ishi@domain.com'); print $hash{Akai}; > akai@domain.com
ハッシュは変数展開の対象にならないので、ダブルクォートで囲んでもそのままの表記が出力されます。
print "%hash\n"; > %hash
keys 関数
keys関数は、ハッシュ変数のすべてのキーをリスト値として返します。ハッシュ変数のすべてのキーのリストを配列に代入する場合は以下のとおりです。
@key = keys( %hash );
キーの格納には乱数を使った手法が使われるため、ハッシュ全体を出力する場合、その順番は保証されません。ですから、@keyには %hash のキーが順序を無視して格納されます。
values 関数
values関数は、ハッシュ変数のすべての値をリストにして返します。
@value = values( %hash );
ハッシュのすべての要素を処理
ハッシュの要素すべてを参照するには、for ループや foreach ループを使います。
%hash = ('Akai', 'akai@domain.com', 'Ishikawa', 'ishi@domain.com'); foreach $key ( keys %hash ) { print "key:$key : value:$hash{$key}", "\n"; } > key:Ishikawa, value:ishi@domain.com > key:Akai, value:akai@domain.com
出力される順番は予測できません。
sort関数でキーをソート
sort 関数は、keys関数が任意にリスト化したキーの順番を、文字コード順で並び替えることができます。
%hash = ('Akai', 'akai@domain.com', 'Ishikawa', 'ishi@domain.com');
foreach $key ( sort keys %hash ) { print "key:$key, value:$hash{$key}", "\n"; } > key:Akai, value:akai@domain.com > key:Ishikawa, value:ishi@domain.com
出力された順番はどのような環境で何度やり直しても同じです。
each 関数
each関数は、ハッシュから次の要素を取り出して、キーと値のペアを返します。すべての要素を取り出すと、未定義を返します。
each関数は、次のようにwhile文と組み合わせることにより、ハッシュのすべての要素にアクセスすることができます。
%hash = ('Akai', 'akai@domain.com', 'Ishikawa', 'ishi@domain.com'); while ( ($key, $value) = each(%hash) ) { print "key:$key, value:$value\n"; } > key:Akai, value:akai@domain.com > key:Ishikawa, value:ishi@domain.com
ハッシュ変数 %hash の各要素のキーと値を順に $key、$valueに代入しながら、ループを繰り返します。each関数はすべての要素を処理し終えると未定義値を返すので、while文がそれを受け取ってただちに終了します。
each関数はキーと値を順次取り出していくので、メモリを無駄に消費しません。その点、すべてのキーをリストにしてから処理するkeys 関数よりも、巨大なハッシュを扱う場合などに有効です。ただし、sortが利かないので、順番を気にする必要があるときは使えません。
キーに対応する値があるかチェック
指定したキーの値があるかを調べるには次のようにします。
# 指定したキー$key の値がある場合 if ( defined($count{$key}) ) { ... }
値が未定義の場合でもキーが存在する場合があります。このばあいは definedでは調べることができません。キーが存在するかどうかは、exists関数を使います。この関数は、ハッシュの要素を引数として受け取り、その要素が存在すれば真を、存在しなければ偽を返します。
# キー$key が登録されている場合 if ( exists($count{$key}) ) { ... }
ハッシュをリストコンテキストで評価
ハッシュをリストコンテキストで評価すると、キーと値が交互に並んだリスト値が得られます。このときのリスト値の順番はランダムなものになっています。
%hash = (a => 1, b => 2); @list = %hash; print "@list"; > b 2 a 1
ハッシュをリストコンテキストで評価したときのリスト値は、キーと値が交互に並びます。それをまたハッシュに代入すると、元のハッシュと同じ要素を持つハッシュを作ることができます。
%hash = (a => 1, b => 2); @list = %hash; %hash2 = @list; # %hash2は%hashと同じ内容になる
ハッシュの要素数を調べる
ハッシュに入っている要素の個数は、keys関数で知ることができます。keys関数をスカラコンテキストで評価すると、引数に渡されたハッシュの要素の個数を返します。
$n = keys( %hash );
ハッシュの消去
ハッシュの要素を初期化するには、 次のよう空のリストを代入します。
%hash = ();
要素を削除するには、 次のように delete 関数を使います。
delete $hash{'Akai'};
3.テクニック
ハッシュの要素値で検索する
ハッシュの値をキーとした新しいハッシュを作成します。
%hash = ("曹操"=>"魏", "劉備"=>"蜀","孫権"=>"呉"); %hash_value = reverse %hash; print $hash_value{'魏'}; > 曹操
上記よりもメモリを効率よく使うには次のようにします。
while ( ($key, $value) = each %hash ) { $hash_value{$value} = $key; }
ただし、これらの方法はハッシュに同じ値がある場合には、最初に見つかったキーだけを見つけだします。
ハッシュを値でソートする
まず、キーか値のリストをソートする必要があります。
%hash = ("YAHOO"=>"YAHOO.CO.JP", "RHYTHM"=>"RFS.JP", "GOO"=>"GOO.NE.JP"); # キーによるソート @keys = sort keys %hash; print "@keys\n"; # 値によるソート @keys = sort { $hash{$a} cmp $hash{$b} } keys %hash; print "@keys\n"
以下の例は、値を数値の降順でソートし、2つのキーが同値であればそれをキーの長さでソートし、それが失敗したならキーのASCII比較を行うものです。
@keys = sort { $hash{$b} <=> $hash{$a} || length($b) <=> length($a) || $a cmp $b } keys %hash;
2つのハッシュからユニークなキーを取りだす
まず最初にハッシュからキーを取りだして、それを配列に格納します。
%seen = (); for $element ( keys(%hash1), keys(%hash2) ) { $seen{$element}++; } @uniq = keys %seen;
簡潔な方法は以下のとおりです。
@uniq = keys %{{%hash1, %hash2}};
よりメモリを節約する場合は以下のとおりです。
%seen = (); while ( defined ($key = each %hash1) ) { $seen{$key}++; } while ( defined ($key = each %hash2) ) { $seen{$key}++; } @uniq = keys %seen;