ゆかりライブの興奮冷めやらぬ中、本日もPerl。
1. 数値のリストを読み込んでソートし、右寄せで表示するプログラム
数値のリストはオライリーからダウンロードできるサンプルコードに入ってるのを使いました。numbersというファイルです。oreilly.co.jp -- Online Catalog: 初めてのPerl 第3版から、どうぞ。といっても、たいした内容でもないので以下に引用。
17 1000 04 1.50 3.14159 -10 1.5 4 2001 90210 666 9 0 2 1 0 2001 42 -40 98.6 2.71828
さて、これを一行ごとに読み込んで数値としてソートします。
#!/usr/bin/env perl -w
use strict;
open NUMS, 'numbers' or die "Can't open the file: $!";
while (<NUMS>) { # 一行ごとに読み込みます
chomp;
print (('-' x 6) . "\n"); # 行ごとの区切りを表示
# 入力行を分割し数値順でソート
my @numbers = sort {$a <=> $b} split;
foreach (@numbers) {
printf "%6d\n", $_; # 右寄せ表示
}
}
close NUMS;ソートに数値比較用のブロックである、{$a <=> $b}を渡しています。実行すると、以下のような感じ。
$ ./ex15-1.pl
------
1
3
4
17
1000
------
-10
1
4
666
2001
90210
#以下略解答とは割と雰囲気が違うコードになってしまいましたが、やってることは同じようなので良いことにしますよ。
2. ハッシュがからんだ複雑なソートを行うプログラム
もちょっとくわしく問題を説明。まず、以下のようなハッシュが有ります。(問題に掲載されていたものをわかりやすく整形)
my %last_name = (
'fred' => 'flintstone',
'Wilma' => 'Flintstone',
'Barney' => 'Rubble',
'betty' => 'rubble',
'Bamm-Bamm' => 'Rubble',
'PEBBLES' => 'FLINTSTONE',
);これは人名のハッシュで名前をキーに姓を記録しています。
このハッシュの内容をソートして表示するのが問題です。ソートの規則はまず、姓を用いてアルファベット順(大文字小文字無視)でソートします。姓が同じ場合は、名前を用いてアルファベット順(大文字小文字無視)にソートします。
で、これを実現するにはsortに適切なサブルーチンを渡してやる必要があります。以下のようにやってみました。
#!/usr/bin/env perl -w
use strict;
# 問題のハッシュ
# last_nameのキーはfirst_name
my %last_name = (
'fred' => 'flintstone',
'Wilma' => 'Flintstone',
'Barney' => 'Rubble',
'betty' => 'rubble',
'Bamm-Bamm' => 'Rubble',
'PEBBLES' => 'FLINTSTONE',
);
# 名字で比較して、名字が同じ時は名前で比較します
sub by_lastname_firstname {
if ("\L$last_name{$a}" lt "\L$last_name{$b}") {
return -1;
}
elsif ("\L$last_name{$a}" gt "\L$last_name{$b}") {
return 1;
}
else { # 名字が同じ時は
return "\L$a" cmp "\L$b"; # 名前で比較します
}
}
# 表示します
foreach (sort by_lastname_firstname keys %last_name) {
print "$_ $last_name{$_}\n";
}by_lastname_firstnameという名前のサブルーチンがこのソートの規則を決めています。実行結果は、
$ ./ex15-2.pl fred flintstone PEBBLES FLINTSTONE Wilma Flintstone Bamm-Bamm Rubble Barney Rubble betty rubble
となって、うまく動いているよう。
さて、解答を見てみると、うちが書いたby_lastname_firstnameサブルーチンにあたるコードがかなりクールでした。これをもとにby_lastname_firstnameを書き直してみましたよ。
# 名字で比較して、名字が同じ時は名前で比較します
sub by_lastname_firstname {
"\L$last_name{$a}" cmp "\L$last_name{$b}"
or
"\L$a" cmp "\L$b";
}う、美しすぎ。

- 作者: ランダル・L.シュワルツ,トムフェニックス,Randal L. Schwartz,Tom Phoenix,近藤嘉雪
- 出版社/メーカー: オライリージャパン
- 発売日: 2003/05
- メディア: 単行本
- 購入: 15人 クリック: 474回
- この商品を含むブログ (294件) を見る