キッズプレート、パスタおかわり

プログラミングやデジモノについてあれこれ
--.--.-- --:--|カテゴリ:スポンサー広告| コメント(-)

スポンサーサイト


上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
2009.09.30 06:30|カテゴリ:Perlコメント(0)

Perlでなんちゃってオブジェクト指向1「名簿をソートしてみる」


 私、一応プログラマの端くれなのでオブジェクト指向ってのをそれなりに勉強しております。ということで今まで自分が勉強してきたことでポイントとなるやもしれんという要所要所を備忘録として思いつき次第書いていこうと思います。ただ小難しい話は苦手なので、

「少なくともこういう処理をするにはこうやったほうが楽ちんだよね?」

 というノリで行こうと思います。使う言語はひらくん大好きPerlです。

 今やPerlにおいてもオブジェクト指向プログラミングが主流となっていると思われます。もともとオブジェクト指向なんていうものと縁もゆかりも無かった言語が現在オブジェクト指向プログラミングの手法を確立している。実はその経緯の中に0からオブジェクト指向を学ぶためのマイルストーンが隠れているのではなかろうかっ! では前置きはこんなところで。

 ある名簿をソートする場合を考えてみます。こんなCSVのファイルがあったとしましょう。

00,A君,13,12,3
01,B君,7,11,7
02,C君,8,4,1
03,D君,3,5,5

「ID,名前,年齢,誕生日(月),誕生日(日)」なんていう名簿です。さてこれを年齢順にソートするとしましょう。

「リファレンスなんてしらない、CSVならスプリットして配列に放り込むのだ」

 というベタなPerlで処理するとこんな感じでしょうか?

※サンプルでは外部ファイルではなく「__DATA__」にレコードを記述しています
※「__DATA__」って何?:ソース内にある「__DATA__」以下の行はハンドルを経由して読み込むことができます
※デバッグなんかに便利やねー
#!/usr/bin/perl
use utf8; #-ソースがUTF8だという宣言
use Encode;
binmode STDOUT, ":utf8"; #-画面に出力したい文字コード
binmode STDERR, ":utf8"; #-エラー出力に使いたい文字コード
binmode STDIN, ":utf8"; #-標準入力から入ってくる文字コード

chomp(@DATA = );#-セパレータ(標準では\n)を削除
@DATA = sort mySort @DATA;#-サブルーチンを使ってカスタムソート

#-出力ブロック
for (@DATA) {
@LINE = split(",",$_);
print $LINE[0] . ':' . $LINE[1] .'=';
print $LINE[3].'月'.$LINE[4] .'日生 ' . $LINE[2] ."歳\n";
}

sub mySort() {
my @A = split(',',$a);
my @B = split(',',$b);
$A[2] <=> $B[2];
}

exit;
__DATA__
00,A君,13,12,3
01,B君,7,11,7
02,C君,8,4,1
03,D君,3,5,5

結果:
03:D君=5月5日生 3歳
01:B君=11月7日生 7歳
02:C君=4月1日生 8歳
00:A君=12月3日生 13歳

 まあ処理結果自体はこれでOKです。ただあまり効率的ではないですね。同一レコードに対して何度もsplitを繰り返しているってのが駄目っぽさをアピールしています。どうしてこのようなことになってしまうのでしょうか。

 項目「ID」「名前」「年齢」「月」「日」はそれぞれが一つのレコードとしてまとまっています。仮にそれぞれの項目を「IDテーブル」「名前テーブル」等のように独立した配列にしてしまうと「年齢でソート」なんていう処理をする際に「他の配列も連動するようにソートをしなければいけません」こんな処理は考えただけで面倒くさいじゃないですか。

 そこで上記のソースでは「1つのレコードを一つの文字列として保持」しておくことでレコードとしてのまとまりを保っているわけです。当然レコード内の項目にアクセスしたければ、その都度splitして値を取り出すことになります。

「複数の項目を一つのまとまりとして保持しておきたい」

 今回のような名簿の並べ替えもそうですが、商品毎の売り上げや自分が運営しているWEBサイトの月別アクセス数等、複数の項目を一つのまとまりとして管理する状況は沢山あります。

 まあ前述のソースでも問題ないのですが項目を取り出すたびにsplitするなんてのは面倒ですよね。

「さまざまな項目を一つのまとまりとして保持して管理する方法」

 は、どうすれば実現できるのでしょうか。そんなおいしい処理をする為にはこーんな手法をとります。配列の要素の中に配列を入れてしまうのです。

 今回のレコードには「ID」というユニーク情報がありますので試しにこいつをkeyにしたハッシュ変数を作成します。そうやって作成したハッシュ変数の値にはsplitで分解した各レコードの情報を「配列のまんま」放り込みます。

#!/usr/bin/perl
use utf8; #-ソースがUTF8だという宣言
use Encode;
binmode STDOUT, ":utf8"; #-画面に出力したい文字コード
binmode STDERR, ":utf8"; #-エラー出力に使いたい文字コード
binmode STDIN, ":utf8"; #-標準入力から入ってくる文字コード

while() {
chomp($_);
my @LINE = split(",",$_);#-常に新しい領域を生み出す「my」がポイント
$Menber{$LINE[0]} = \@LINE;#-配列のリファレンスを入れる
}

for $key (sort mySort keys %Menber) {
print $Menber{$key}[0] . ':' . $Menber{$key}[1] .'=';
print $Menber{$key}[3].'月'.$Menber{$key}[4] .'日生 ' . $Menber{$key}[2] ."歳\n";
}

sub mySort() {
$Menber{$a}[2] <=> $Menber{$b}[2];
}

exit;

__DATA__
00,A君,13,12,3
01,B君,7,11,7
02,C君,8,4,1
03,D君,3,5,5

 最初のwhile構文が今回の重要なポイントです。

1 読み込んだ一行をsplitで分解し配列@LINEに入れます。
2 @LINE(正確には@LINEのリファレンス情報)を$Menber{$LINE[0]}に入れます。

 いかがでしょうか? わかりやすく書くとこんな感じです。

$Menber{'00'} = ['00','A君','13','12','3'];

 あたかも$Menber{'00'}という変数の中に配列の構造をそのまま取り込んでいるような処理になっています。
 この構造にアクセスするには$Menber{'00'}を通常の配列変数ととらえて$Menber{'00'}[0]なんて感覚でアクセスできます。
 これでIDというユニークなキーを使って各項目の配列に自由にアクセスできるようになりました。
 ソート用のサブルーチンの中では配列の比較対象である年齢(3番目の項目)を使ってソートし、結果のプリントでは保持してある構造に直接アクセスして値をプリントしています。

 このように「複数の項目を一つの塊にまとめる」という手法を覚えると、データ処理の効率は飛躍的にあがります。

 今回は$Menber{'00'}の中に項目の塊をどーんと放り込んでみました。

・1行目のレコードを読み込んで項目ごとに分解
・分解した項目を一つの塊として変数に入れておく

 こうやって書いてみるとなんでもない処理ですが注目して欲しいのは複数に分裂したレコードの項目を寄せ集めて「一つの塊」にしていることです。

 一つ一つのデータを決められた枠組みのなかに入れて、ぽんぽん新しいデータの塊を生み出す。生み出すなんて言うとなんだかとってもアナログな感じがして楽しいですよねー。

 さて今回はここまで。次回はまだ未定ですが、もうちょっとそれらしくしたオブジェクトプログラミングをご紹介しようと思います。
コメントの投稿












管理者にだけ表示を許可する
トラックバック
この記事のトラックバックURL

プロフィール

ひらくん Author:ひらくん
どもども、ひらんくんどす。
日々まったり過ごしております。
仕事はDTP関連のスプリクト&アプリケーション開発。
Follow happyscript on Twitter

ブログ内検索



上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。