【しばらく編集不可モードで運営します】 編集(管理者用) | 差分 | 新規作成 | 一覧 | RSS | FrontPage | 検索 | 更新履歴

Perlのsort関数 - 数値のソートに挑戦したのですが…

目次

数値のソートに挑戦したのですが…

sort 関数を使用すると、文字列に対してのソートを 行うことがわかった。

 @arr = (2, 44, 11, 45);
 @sorted_list = sort(@arr);
 print join(', ', @sorted_list);

 - 結果 -
 11, 2, 44, 45

それで、整数に対してのソートを行うような Perl スクリプトを 書こうと調べてみると、以下のようなサンプルが見つかった。

 @arr = (2, 40, 44, 23, 234, 44);
 
 sub by_number {  
   if ($a < $b) {
     return -1;
   } elsif ($a == $b) {
     return 0;
   } elsif ($a > $b) {
     return 1;
   }
 }
 
 @sorted_list = sort by_number(@arr);
 print join(', ', @sorted_list);
  
 - 結果 -
 2, 23, 40, 44, 44, 234
 
このスクリプトは、次のものと等価ということも分かった

 @sorted_list2 = sort { $a <=> $b } @arr;
 print join(', ', @sorted_list2);
 
 - 結果 -
 2, 23, 40, 44,44, 234

しかし、Perl を学びはじめて、わずかしか経過していないので、 by_number サブルーチンが何を行っているかがわからない。 (<=> は、等しければ 0, $a が大きければ 1, $b が大きければ -1 ということが本に書いてあった)

関数にリストを渡すと、@_ に渡されたリストが入り、 $_[0] で先頭の、$_[1] にその次の値が入ることが分かった.

 sub my_print {
   $result = join(', ', @_);
   print '$result = ', $result, "\n";
   print '$_[0] = ', $_[0], "\n";
   print '$_[1] = ', $_[1], "\n";
 }
 
 @arr = (100, 200, 300);
 my_print(@arr);
 
 - 結果 -
 
 $result = 100, 200, 300
 $_[0] = 100
 $_[1] = 200

だが、by_number サブルーチン内で, これを試すと…

 @arr = (2, 40, 44, 23, 234, 44);
 
 sub by_number {
   $result = join(', ', @_), "\n";
   print '$result = ', $result, "\n";
   print '$_[0] = ', $_[0], "\n";
   print '$_[1] = ', $_[1], "\n";
   
   
   if ($a < $b) {
     return -1;
   } elsif ($a == $b) {
     return 0;
   } elsif ($a > $b) {
     return 1;
   }
 }
 
 sort by_number(@arr); # by_number(@arr); の場合は、期待するものが表示される

sort が付いていると、何も表示されなくなる。

どのような仕組みになっているのでしょうか? sort はリストを受け取るサブルーチンだと理解しているのですが、 上記の by_number の仕組みが良く分からない($a, $b が何なのか)。

これを理解するうえで参考になるスクリプトなど、教えていただけないでしょうか?

結論

sort 関数には、次のような使い方がある。

SUBNAME がある場合には、LIST をどのように 並べるかに応じて使い分ける。(このルーチンは、 再帰ルーチンであっては、ならない)

サンプル

 @arr = (100, 23, 45, 33, 22);

 @sorted_list1 = sort { $a <=> $b } @arr;
 print join(', ', @sorted_list1), "\n";

 @sorted_list2 = sort { $b <=> $a } @arr;
 print join(', ', @sorted_list2), "\n";

 %hs = (
   Taro => '011-333-344',
   Jiro => '222-432-455',
   Hanako => '444-234-555',
   );

 foreach $key (sort keys %hs) {
   print "$key = $hs{$key}\n";
 }

 - 結果 -
 22, 23, 33, 45, 100
 100, 45, 33, 23, 22
 Hanako = 444-234-555
 Jiro = 222-432-455
 Taro = 011-333-344



sortが呼び出すサブルーチンの引数は $_[0], $_[1]を介さずに、変数$a, $bを介して引数が渡されます。

ラクダ本(オライリー・ジャバン社刊の『プログラミングPerl』のことです) でも解説されていますし、 http://www.att.or.jp/perl/man/perlfunc.1.html というページにも説明がありますから、ご覧になってはいかがでしょうか。