ハッシュ(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 関数を使ったループは、わざわざキーの配列などを作る必要がないのでコストが低いとの事。適材適所ですね。