ゆかりライブの興奮冷めやらぬ中、本日も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件) を見る