Home / Menu

CGI-Perlの基礎講座

CGI-Perlの基礎講座(p07)

(本ページは、KENT WEBのFantasyボードプログラムをステップ単位に説明しています。)

◆ ソート(sort関数)

・概要

パールでは結構よく使うsort関数、ソートについてです。
ちなみに、sort関数はC言語にはありません。UNIXのコマンドではsortコマンドをよく使います。
では、以下に説明いたします。


@result = sort { $a <=> $b } @list;

上記は、一般的なsort関数の書式です。
突然、$a, $b がでてきますが、これは、
Perlのインタプリタが、比較する2つの値(配列の要素)をセットします。
sort{ } は並べ替えるための大小比較の関数を定義するものです。

{$a <=> $b}
とすれば昇順、
{$b <=> $a}
とすれば降順になります。

また、応用として、


@name = ( 'taro', 'jiro', 'saburo', 'shiro');
%height = ( 'taro' => 176, 
'jiro' => 185,
'saburo' => 160,
'shiro' => 170 );


こんなハッシュが定義されている場合に

sort { $height{$a} <=> $height{$b} } @name 

とすると %height の値によってソートされて、
('saburo', 'shiro', 'taro', 'jiro')
という配列が返ります。


sortには3つの構文があります。 1:sort LIST 2:sort SUBNAME LIST 3:sort BLOCK LIST の3つです。 一番目は比較的簡単な用法です。 例えば、 @list = (0,1,2,3,4,5,6,7,8,9,10,11,12); の時、 @result = sort @list; とすると、@listには、 (0,1,10,11,12,2,3,  ,9)となります。 これを数値の値順にしたいときに2番目と3番目の構文を使います。 まず、2番目の構文を使う場合、二つの数値を比較する次のようなサブルーチンが必要になります。 sub number {   if ($a < $b) {     return -1;   } elsif ($a == $b) {     return 0;   } elsif ($a > $b) {     return 1; } } ただこのサブルーチンは、記述が長くて面倒なので、そこで便利な「 <=> 」という演算子を使うと次のように簡単に記述す る事ができます。 sub number { $a <=> $b; } スッキリしましたね。 さて、このサブルーチンを利用してsortの第2の構文を使い、 @result = sort number @list; と記述します。これで@listには、 (1,2,3,4,5,6,7,8,9,10,11,12)というリストになります。 プログラム中でこのようなソートを複数回使うのなら、サブルーチンもいいのですが、 一度しか使わないなら、sortの3番目の構文を使ってサブルーチンの定義をしなく て済みます。次のように記述します。 @result = sort {$a <=> $b } @list;
尚、数値の比較は <=> で、文字列の比較は cmp を使用します。 例1、「@hogehoge」という配列データが以下のようにあったとして --- ここから --- aaa,bbb,1,ccc ddd,eee,99,fff ggg,hhh,3,iii jjj,kkk,2998,lll --- ここまで --- これを、各行の内容のカンマで区切られている3つ目の情報(つまり、1,99,3,2998)でソート(少ない順/多い順)するの には、どうしたらいいのでしょうか? @sortdata = sort { (split(/\,/,$a))[2] <=> (split(/\,/,$b))[2] } @hogehoge; 補足:多い順(3,2,1)は @sortdata = reverse sort { (split(/\,/,$a))[2] <=> (split(/\,/,$b))[2] } @hogehoge; 例2、配列が下記のようなものだった場合で、配列に記録されている日付順に並べるには。 --- ここから --- aaa,bbb,1999/11/08(月) 11:00:50,ccc ddd,eee,1999/10/14(木) 10:16:46,fff ggg,hhh,1999/07/28(水) 09:20:05,iii jjj,kkk,1999/11/11(木) 08:46:42,lll --- ここまで --- @sortdata = sort { (split(/\,/,$a))[2] cmp (split(/\,/,$b))[2] } @hogehoge;

イヴァル(eval関数)

・概要

いまいち、理解できないeval関数、イヴァルについてです。
この際、マスターしちゃいましょう!
では、以下に説明いたします。


eval関数に渡す文字列を Perl プログラムとして解釈し、それを実行する命令です。

$rc = eval($expr);

$rc は、最後に評価した値、または return 関数で返された値。エラー時は未定義(undef)。
$expr は、式 or ブロックで、省略時は $_ が使用されます。
また、perlがエラーメッセージを出して終了するような命令や、dieが実行された場合、undefineを返し、
$@にエラーメッセージを格納されます。

例1、

     print "3 * (5 + 3)" . "\n";             # 文字列 3 * (5 + 3) が表示

     print eval("3 * (5 + 3)") . "\n";       # 24が 表示される

例2、

foreach文で、データファイルからレコードを($Data1,$data2・・・$data100)のように読み込んだ際に、
例えば $data80 の値を操作したい場合、「80」をフォームから入力させ、
文字列「$data」に「80」を付加してプログラムの中で、
$data80=の様に変数として扱いたい時、どのようにすればよいでしょうか?


$num = '80';
$in = 100;
$data80 = 0;

eval "\$data$num = $in";

これで、$data80に$inの値(100)が入ります。

例3、

0除算の可能性のある割り算を行う際、evalを用いてperlが異常終了するのを防ぐ事がでます。。 


          $x = 10; $y = 0;
          $ans = eval { $x / $y; };
          if ($@) { warn "WARNING: $@"; }

例4、

dbmopen, symlink, flockなど、実装されているかどうか分からない命令を、
evalを用いてperlが異常終了するのを防ぐ事ができます。 (eval { ... }; のセミコロン( ; )に注意) 


          open(OUT, "> xx");
          eval { flock(OUT, 2); };
          if ($@) { warn "WARNING: flock isn't supported.\n"; }


以上、今回は、ソートとイヴァルをお勉強しました。間違えや御感想があれば、遠慮なくお申しください。

Home / Menu