ハッシュ(2) ハッシュとループ
今度はハッシュの中にある値をそれぞれループで処理したいと思います。
最初は foreach $value (%hash) でできるかと思い、以下のように書いてみました。
# hash2.pl
my %capital_city = (
Japan => 'Tokyo',
USA => 'Washington',
England => 'London',
);
foreach $capital (%capital_city) {
print "$capital\n";
}
これを実行すると……
England London USA Washington Japan Tokyo
と、キー、値、キー、値……の順番で出力される事がわかりました。でも、順番はバラバラですね。ハッシュの特徴として「順番は保存されない」ので、foreachなどで取り出しても順番は再現されません。
本やウェブで調べると、ハッシュのループには普通 keys 関数を使うようです。keys 関数は、引数として渡したハッシュの全てのキーを1つの配列にして返してくれます。ただし、順番はバラバラです。
そこで、アルファベット順に処理する為に sort 関数を使って、keys で得た配列をソートします。
# hash3.pl
my %capital_city = (
Japan => 'Tokyo',
USA => 'Washington',
England => 'London',
);
for (sort keys %capital_city) {
print "The capital of $_ is $capital_city{$_}.\n";
}
for と foreach は同じ意味でした。また、foreach で受け取る変数を省略すると自動的に $_ が使われるんでしたね。
実行結果です。
The capital of England is London. The capital of Japan is Tokyo. The capital of USA is Washington.
ちゃんとアルファベット順に出力されました。対応関係もバッチリです。
他にも、values 関数を使えば値の配列を取り出せます。
# hash4.pl
my %capital_city = (
Japan => 'Tokyo',
USA => 'Washington',
England => 'London',
);
for (sort values %capital_city) { print "$_\n"; }
実行結果です。
London Tokyo Washington
値だけが表示されます。
他のループ方法もあります。each 関数を使えばハッシュからキーと値からなる2要素のリストを1つずつ得る事ができます。
each 関数を呼ぶ度にハッシュ内部のイテレータが1つ進むので、ハッシュ内の全要素を列挙できます。イテレータがハッシュの最後まで到達した時、each 関数は空リストを返し、イテレータを先頭に戻します。
ただし、each 関数が返すキーと値の順番もやはりバラバラなので注意が必要です。
# hash5.pl
my %languages = (
Perl => 'Larry Wall',
Ruby => 'Yukihiro Matsumoto',
Python => 'Guido van Rossum',
);
while (($lang, $author) = each %capital_city) {
print "The author of $lang is $author.\n";
}
while の条件部にeachで得たリストの代入文を書いています。代入文を評価する場合、代入後の左辺値が値として得られます。each 関数を呼び出していき、ハッシュの最後のペアまで到達すると、空リストが返りますが、空リストは偽(false)として評価されるので、そこで while ループが終了します。
実行してみます。
The author of Python is Guido van Rossum. The author of Ruby is Yukihiro Matsumoto. The author of Perl is Larry Wall.
順番はバラバラですね。(^_^)
each 関数を使ったループは、わざわざキーの配列などを作る必要がないのでコストが低いとの事。適材適所ですね。