0o0dグッ

CGI-Perlの基礎講座

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

燈明日記インデックス/Chaichan-World !/法華経ノート/オブジェクト指向/シェルスクリプト