Perl

ハッシュ(連想配列)のソート

Perlでのハッシュのソートについてのメモです。普段よくやってるはずなんですが、それでもど忘れしてしまうので。

Perlのハッシュは作成時のキー順はまったく保証されないので、並び替えする場合はキーか値のどちらかの配列をソートして使用します。

キーでソートする

sort演算子を使います。keysでキーの配列を得てソートした結果を受け取ります。

my %score = ( 'い' => 1080, 'ろ' => 216, 'は' => 324 );

my @members = sort { $a cmp $b } keys %score;

print "content-type: text/plain; charset=utf8\n\n";
print "メンバー一覧\n";
for my $name ( @members ) {
  print "$name: $score{$name}\n";
}
> メンバー一覧
> い: 1080
> は: 324
> ろ: 216

値でソートする

同じくsortを使って、並び替えられた結果のキーの配列を受け取ります。比較を値で行ないます。数値での比較にはスペースシップ演算子(<=>)を使います。また、得点ランキングとして大きい数字が最初に来るように$b <=> $a$a$bを逆に)としています。

my %score = ( 'い' => 1080, 'ろ' => 216, 'は' => 324 );

my @winners = sort { $score{$b} <=> $score{$a} } keys %score;

print "content-type: text/plain; charset=utf8\n\n";
print "得点ランキング\n";
for my $name ( @winners ) {
  print "$name: $score{$name}\n";
}
> 得点ランキング
> い: 1080
> は: 324
> ろ: 216

同点者がいた場合は、キー名順にならべるように追加したところ。sortでは$a$bが同点だった場合は0が返ります。同点だった場合はキー名を文字列でソートします。

...
$score{'や'} = 1080;
@winners = sort { $score{$b} <=> $score{$a} or $a cmp $b } keys %score;

print  "得点ランキング\n";
for my $name ( @winners ) {
  print "$name: $score{$name}\n";
}
> 得点ランキング
> い: 1080
> や: 1080
> は: 324
> ろ: 216

値がリファレンスの場合のソート

値がハッシュリファレンス、という程度ならボクでも簡単です。

...
my %members = (
  'い' => { 'score' => 1080, 'age' => 30 },
  'ろ' => { 'score' => 216,  'age' => 25 },
  'は' => { 'score' => 324,  'age' => 18 },
  'や' => { 'score' => 1080, 'age' => 60 }
);


@winners = sort { $members{$b}->{'score'} <=> $members{$a}->{'score'} or $a cmp $b } keys %members;

print  "得点ランキング\n";
for my $name ( @winners ) {
  print "$name: ${members{$name}->{'score'}}\n";
}
> 得点ランキング
> い: 1080
> や: 1080
> は: 324
> ろ: 216