« Perlでソート関数を使う | トップページ | コマンドのリファレンス »

2005/01/24

Perlで2次配列をソート関数でソートする

引き続き、Perlでのsort関数での話題です。
2次配列でsort関数を使おうとすると、一気にハイレベルになります。

最初に答えを書いてしまうと、
2次配列 @data があるとして、数値 $data[0][0] と $data[1][0] と $data[2][0] を 昇順にソートします。

@data = sort { @$a[0] <=> @$b[0] } @data;

という式になります。
一見理解できそうですが、よく見るとすごくややこしかったりします。
変数の参照、参照変数の逆参照、無名配列、配列のスライス、というのが理解できていないと理解できません。

まず、$a、$b に何が入っているかというと、
$data[0]、$data[1]、$data[2] のどれかです。
$data[0]には、二次元目の無名配列[0]の参照しているアドレスが入っています。
$data[0][0] は、$data[0]->[0] と同じ意味なので、$data[0]->[0] と考えた方が解りやすいかもしれません。

つまり、$aは二次元目の配列の参照変数なわけです。
それを、@$a として、配列に戻しています。
つまり、$aを$data[0]と考えると、 @{$data[0]} と逆参照したことになります。

@$a[0]の [0]の部分ですが、これは配列の要素を表しているのではありません。
配列 @$a の中から要素0をスライスしています。

スライスの簡単な例として、現在の日付を取得する方法があります。
普通は、
($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime( $time );
として現在の日時すべてを取得しますが、
($mday, $mon, $year) = (localtime( $time ))[3,4,5];
とすれば、余分な変数が要りません。

つまり、@$a[0]の [0]の部分では、
配列の中から要素0のみを取り出して配列を返しています。
結果的に返された配列が1つだけなので、要素0の値のみが返って来ます。
よって、$a が$data[0] だった場合、$data[0][0] の値が取り出せることになります。


2次配列をソートできるようになると、

$data[0][0] = 20; $data[0][1] = "山田";
$data[1][0] = 15; $data[1][1] = "田中";
$data[2][0] = 30; $data[2][1] = "佐藤";

といったデータを、数値順に名前を取り出せます。
たとえば、

@data = sort { @$a[0] <=> @$b[0] } @data;
$data[0][0] = 15; $data[0][1] = "田中";
$data[1][0] = 20; $data[1][1] = "山田";
$data[2][0] = 30; $data[2][1] = "佐藤";

にソートされます。


2006/11/08 追記
なんかここを見てくださっている方もいらっしゃるようなので、追記です。
上の方法でもソートできますが、配列の逆参照なんて使わなくてもできます。(汗)

上の例だと、
@data = sort { $a->[0] <=> $b->[0] } @data;

でOKです。
$a と $b は
$data[0]~$data[2]のことだから、2次元目の[0]は
$a->[0]、$b->[0] で取れますよね。

|

« Perlでソート関数を使う | トップページ | コマンドのリファレンス »

Perl」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)


コメントは記事投稿者が公開するまで表示されません。



トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/54336/2675110

この記事へのトラックバック一覧です: Perlで2次配列をソート関数でソートする:

« Perlでソート関数を使う | トップページ | コマンドのリファレンス »