Perl Perl_4
Perl ソート再び 数値順 sort, スペースシップ演算子 (0x24a)
目次 - Perl Index
Theme
Perl について、復習を兼ねて断片的な情報を掲載して行く連載その 0x24a 回。
Perl で、リストデータを「 ソート 」( 分類する, 整列させる ) する演算子「 sort 」を改めて確認する。この Perl の「 sort 」については (0x2a) で一度確認しています。
sort の書式
まずはじめに、改めて演算子「 sort 」の書式を確認しておきます。
sort SUBNAME LIST
sort BLOCK LIST
sort LIST
この書式の内、(0x2a) で確認をしたのは 3 番目の「 sort LIST 」の動作のみでした。
コードポイント順
最もシンプルな書式「 sort LIST 」を利用する場合、演算子「 sort 」は、「 LIST 」を「 コードポイント順 」、つまり、文字列比較でソートします。
my @chr = sort qw/ C A E B D /;
# A B C D E
print "@chr\n";
これは、簡素で便利ですが、数値をソートする場合には、おそらく意図していない並べ替えを行います。
my @num = sort qw/ 99 98 101 100 /;
# 100 101 98 99
print "@num\n";
(0x2a) では、適切に数値をソートする演算子「 <=> 」( スペースシップ演算子 ) を少しだけ確認しました。
「 <=> 」を使うには、「 sort BLOCK LIST 」の書式を使います。
my @num = sort { $a <=> $b } qw/ 99 98 101 100 /;
# 98 99 100 101
print "@num\n";
スカラ変数「 $a 」と「 $b 」は、Perl で予め予約された特別な変数です。ですから、通常プログラム内で任意に利用することは出来ません。詳細は perlvar - perldoc.jp や sort - perldoc.jp を確認してみてください。
今回は、数値を並べ替える際の「 sort 」の動作を確認してみます。
並べ方を伝えるためのサブルーチン
書式にある「 sort SUBNAME LIST 」は、サブルーチン「 SUBNAME 」を引数として「 sort 」に渡す形式です。
通常「 サブルーチン 」は、 (0x2f) 等で確認したように、「 特定の処理をするためのひとかたまりのコード 」で、ユーザが定義した関数のことを意味します ( 少なくとも Perl では )。
「 sort 」に渡すサブルーチンも同様に、ひとかたまりの処理をまとめたものですが、それは「 sort 」( Perl ) に並べ方を伝えるための「 sort-definition subroutine 」( ソート定義サブルーチン ) である必要があります。
実のところ、前述したスペースシップ演算子「 <=> 」は、数値を正しく並べるソート定義サブルーチンのショートカットのようなものだと理解しています。
数値を並べ替えるサブルーチン
リストされたデータは、常に 2 つの値で比較されます。このため、「 sort 」は 2 つの値の入れ物としてスカラ変数「 $a 」と「 $b 」を予め持っています。
それから、「 sort 」は「 $a を $ b より前に置く 」場合の値、「 $a を $b より後ろに置く 」場合の値、「 $a と $b に順番を付けられない 」場合の 3 つの値を受け取ります。
この 3 つの値は次のように「 -1 」「 0 」「 1 」の数値で表されます。
$a を $b より前に置く -1
$a と $b に順番をつけられない 0
$a を $b より後に置く 1
「 sort 」のためのソート定義サブルーチンは、この 3 つの値を適切に返す処理を定義するだけ構いません。あとは「 sort 」( と Perl ) がよしなに並べ替えを行ってくれます。
例えば、数値を昇順 (小さい順) で並べるには、次の様なソート定義サブルーチンを書くことが出来ます。
sub by_number {
if ($a < $b) { -1 } elsif ($a > $b) { 1 } else { 0 }
}
このプログラムは、まず、「 $a が $b より小さい 」場合に「 -1 」を返して「 $a 」を「 $b 」より前に置きます。
もし、「 $a が $b より大きい 」場合は「 1 」を返して「 $a 」を「 $b 」より後ろに置きます。
「 $a が $b より大きくも小さくもない 」場合は、順番を付けられないので「 0 」を返します。
このソート定義サブルーチンを「 sort 」の引数として指定してあげれば、適切にソートされた数値を得ることが出来ます。
my @numbers = qw/ 111 98 99 100 101 /;
# サブルーチン by_number を指定する
my @result = sort by_number @numbers;
# 数値が昇順で正しく並ぶ
# 98 99 100 101 111
print "@result\n";
なお、ソート定義サブルーチンを「 sort 」に指定する場合は、サブルーチンを表すシジル「 & 」は付けません。
また、サブルーチンの名前「 SUBNAME 」は、スカラ変数に格納した文字列でも利用可能です。
my $subname = 'by_number';
# SUBNAME にスカラ変数を指定
my @num = sort $subname qw/ 99 98 101 100 /;
なんだか便利そうですね。
「 <=> 」とサブルーチン
前項のソート定義サブルーチンは、スペースシップ演算子「 <=> 」を利用した次の記述と同じ動作をします。
my @result = sort { $a <=> $b } @numbers;
数値を「 降順 」で並べたい場合は、次のように「 $a 」と「 $b 」の位置を入れ替えれば済みます。
my @result = sort { $b <=> $a } @numbers;
これは、前項のソート定義サブルーチンでも同じことで、「 $a 」と「 $b 」の位置を入れ替えれば降順で並べることが出来ます。
sub by_number {
if ($b < $a) { -1 } elsif ($b > $a) { 1 } else { 0 }
}
そうといっても、サブルーチンの定義や「 $a 」と「 $b 」の入れ替えの手間を考えると、数値の並べ替えは、素直にスペースシップ演算子「 <=> 」を使った方が良さそうです。
0x24a -> 0x24b へ
次回は、スペースシップ演算子と同じく 3 文字の名前をもつソートのための演算子「 cmp 」を確認します。
参考情報は書籍「 初めての Perl 第 6 版 」を中心に perldoc, Wikipedia および各 Web サイト。それと詳しい先輩。
目次 - Perl Index
Perl mp2 翻訳 Web コンテンツ圧縮の FAQ (d228)
Perl mp2 翻訳 既知のブラウザのバグの回避策をいくつか (d227)
Perl mp2 翻訳 Perl と Apache でのキュートなトリック (d226)
Perl mp2 翻訳 テンプレートシステムの選択 (d225)
Perl mp2 翻訳 大規模 E コマースサイトの構築 (d224)
Perl mp2 翻訳 チュートリアル (d223)
Perl mp2 翻訳 既知のブラウザのバグの回避策をいくつか (d227)
Perl mp2 翻訳 Perl と Apache でのキュートなトリック (d226)
Perl mp2 翻訳 テンプレートシステムの選択 (d225)
Perl mp2 翻訳 大規模 E コマースサイトの構築 (d224)
Perl mp2 翻訳 チュートリアル (d223)