« 2004年12月 | トップページ | 2005年2月 »

2005年1月

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] で取れますよね。

| | コメント (0) | トラックバック (0)

2005/01/23

Perlでソート関数を使う

Perlには sort という便利な関数があります。
配列(リスト)を、順番に並べてくれます。
書式は、一般的な関数とは違っていて、ちょっとややこしいです。

1、  @list_b = sort subname @list_a;
2、  @list_b = sort { $a <=> $b } @list_a;
の2つあります。

1の例だと、
@list_b = sort subsort @list_a;
sub subsort {
  return $a <=> $b;
}
という書き方になります。
subsortというのはサブルーチン名で、&subsort( ) と書かないところがややこしいところです。
$a、$bというのは、@list_aの要素のうちの2つの参照です。変数名は必ず $a 、 $b になります。
サブルーチン subsortは、同じパッケージ内に無いといけません。
return で返される値は、-1、0、1 のいずれかになります。
-1が返ると $a が前に、0だとそのまま、1だと $b が前に並べ替えられます。
つまり、サブルーチンの中は、-1か0か1を返せるようになっていれば良いわけです。

ってな感じで、一般的なPerlの法則とはちょっと違ったルールが適用されています。
ちなみに $x <=> $yの <=> 演算子は、$x が $y より小さい場合は -1、等しい場合は 0、$x が $y より大きい場合は 1 を返します。
文字列の場合は、 $x cmp $y と書けば、同じく 小さいか、同じか、大きいかによって -1、0、1 のどれかが返って来ます。

私が良く使う例として、
@list_b = sort subsort @list_a;
sub subsort {
  if ( length( $a ) < 1 and length( $b ) > 0 ) {
    return -1;
  } elsif ( length( $a ) > 0 and length( $b ) < 1 ) {
    return 1;
  } elsif ( length( $a ) < 1 and length( $a ) < 1 ) {
    return 0;
  }
  return $a cmp $b
}
ってなのがあります。
これは文字列を、空白文字を一番最後に、昇順にソートします。

これが理解できれば、
2の例も似たようなものだというのが解ると思います。
サブルーチンにしているのか、ブロックにしているのか、という違いだけです。
簡単な比較ならブロックで済むし、複雑なソート条件があるなら、サブルーチンにして処理できます。
@list_b = sort { $a <=> $b } @list_a; だと数値を昇順にソートし、
@list_b = sort { $b <=> $a } @list_a; だと数値を降順にソートします。

| | コメント (0) | トラックバック (0)

LunascapeでSUNのJavaを使う方法

WindowsのIEでSUNのJavaを使う場合、最近のJavaはインストールすると自動でプラグインの設定もしてくれるので、深く考えずにSUNのJavaを使うことが出来ます。
Javaのランタイムの取得は、http://java.com/ja/からダウンロードできます。
Javaの開発ツールは、http://java.sun.com/からダウンロードできます。
Ver.1.3ごろまでのJavaは、ブラウザで起動させる設定が大変でした。(汗)

IEで使用する場合、Windowsの「スタート」→「コントロールパネル」にあるJava Plug-inを開き、ブラウザの項目のInternet Explorerにチェックが入っていればOKです。
IE起動後、IEの「ツール」→「インターネットオプション」→「詳細設定」で、Java(SUN)の項目にチェックが入っていればOKです。

ですが、IEコンポーネントを使ったブラウザでは、上記の設定だけではSUNのJavaを使うことが出来ません。
私はメインのブラウザにLunascapeを使用していますが、Lunascape1を使っていた頃にこの問題にぶつかり、悩みました。
同じくIEコンポーネントを使用しているSleipnirに関する情報の中から、この問題の解決策を見つけました。

IEコンポーネントを使用すると、IEの設定とは無関係にMS-VMを優先的に使用するようです。
だから、MS-VMを直接停止させる必要があります。
Windowsの、「スタート」→「ファイル名を指定して実行」に、
regsvr32 /u msjava.dll
と入力します。
確認を求めるダイアログが出ますが、OKを押します。
これで、Lunascape1でもSUNのJavaが使えるようになりました。
Lunascape2でも同じ方法で使えます。

ちなみに、
regsvr32 msjava.dll
と入力すると、停止させていたMS-VMを起動させることが出来ます。
作成したAppletがMS-VMで使えるのかどうか確認する時に役立ちます。

| | コメント (0) | トラックバック (0)

2005/01/08

Vine Linux でUSBメモリを使う

私はUSBメモリのMP3プレーヤーを愛用しています。
データのMP3変換はWindows上で行っているので、Windowsからデータを移動しているのですが、せっかくLinuxをファイルサーバにしているんだから、Linuxから直接データを移動できれば便利かなと思って、VineLinuxでUSBメモリを使う方法を探した所、@ITに情報がありました。

USBフラッシュメモリを使うには
USBメモリを一般ユーザーがマウントできるようにするには

今のLinuxは自動でUSBメモリを認識するみたいですね。
USBメモリはSCSIデバイスとして認識されるので、SCSIをマウントするのと同じなのですが、USBメモリがどのSCSIデバイス名になっているのかはいまいち不明でした。(汗)
で、@ITのサンプルと同じように /dev/sda1 をマウントした所、ちゃんとマウントできました。

一般ユーザーがマウントできるように /etc/fstab を修正したところ、GNOMEのデスクトップ画面にUSBメモリ用のショートカットが自動的に作成されていました。
この辺が、Windowsを使う感覚とは全く違うところですね。
ちなみに、念のために iocharset=euc-jp も記入しました。

「USBフラッシュメモリを使うには」では、マウント時にvfatであることを指定しているのに対し、「USBメモリを一般ユーザーがマウントできるようにするには」では、特にそのような指定がありませんでしたが、どちらとも正常に読み込み&書き込みができました。
この辺は謎です。(汗)

| | コメント (0) | トラックバック (0)

« 2004年12月 | トップページ | 2005年2月 »