2013年2月19日火曜日

複数条件でソート

ソートは複数の条件を指定することができます。


%dic=();
$dic{'a'} = 0;
$dic{'b'} = 1;
$dic{'c'} = 2;
$dic{'d'} = 0;
$dic{'e'} = 2;
$dic{'f'} = 3;
$dic{'g'} = 0;

# 複数条件でソート
@sorted_keys = sort {$dic{$b} <=> $dic{$a} or $b cmp $a} keys %dic;                                        

foreach $key(@sorted_keys) {
    print "$key:$dic{$key}\n";
}


上の例では、ハッシュの値の降順にソートし、値が同じ場合はハッシュのキーの降順でソートする例です。

結果は以下のようになります。

f:3
e:2
c:2
b:1
g:0
d:0
a:0


orの左側に第一条件を指定し、もし第一条件が同じ値だった場合、次の条件をorの右側に指定します。条件が2つより多い場合は、更にorを続けて3番めの条件、4番めの条件、・・・というように続けることができます。

あまり条件が長くなると1行に書くのが分かりづらくなるようであれば、以下のようにソート条件を関数化することもできます。



%dic=();
$dic{'a'} = 0;
$dic{'b'} = 1;
$dic{'c'} = 2;
$dic{'d'} = 0;
$dic{'e'} = 2;
$dic{'f'} = 3;
$dic{'g'} = 0;

# ソート条件を関数呼び出しで
@sorted_keys = sort sort_routine keys %dic;

foreach $key(@sorted_keys) {
    print "$key:$dic{$key}\n";
}

sub sort_routine
{
    $dic{$b} <=> $dic{$a}
    or
    $b cmp $a
    or
    # もっといろんな条件
}







UTF8でファイル入出力

ファイルをオープンする時に文字コードを指定することができます。


open($ハンドル変数, "<:utf8", 入力ファイル名);
open($ハンドル変数, ">:utf8", 出力ファイル名);


上記でUTF8でファイルオープンします。

オープンのたびにいちいち指定するのが面倒な場合、以下のように指定することもできます。


use open IN => ":utf8";
use open OUT => ":utf8";


上記のIN / OUTはファイルハンドルではありません。
上記の指定で入力・出力フィルのオープン時にいちいち":utf8"等と文字コードを指定しなくてもよくなります。

また、上の2行もめんどうな時は、次のように1行ですますことも可能です。

use open IO => ":utf8"; # 入出力ファイルの文字コードをいっぺんに指定





ハッシュ(辞書)を値の順にソートする

ハッシュ(辞書)を値の昇順にソート


%hash = ();
$hash{'a'} = 1;
$hash{'b'} = 3;
$hash{'c'} = 5;
$hash{'d'} = 2;
$hash{'e'} = 4;

# ハッシュを値の昇順にソート
@sorted_key = sort {$hash{$a} <=> $hash{$b}} keys %hash;

foreach $key(@sorted_key) {
    print "$key:$hash{$key}\n";
}


実行結果は以下の様になります。


a:1
d:2
b:3
e:4
c:5



注意が必要なのは、ハッシュは配列のように数値のインデックスがあるわけではないのでsort関数で帰ってくるのはキーの配列だということです。

上記の$aと$bを入れ替えれば降順に出力されるようになります。


%hash = ();
$hash{'a'} = 1;
$hash{'b'} = 3;
$hash{'c'} = 5;
$hash{'d'} = 2;
$hash{'e'} = 4;

# ハッシュを値の降順にソート
@sorted_key = sort {$hash{$b} <=> $hash{$a}} keys %hash;

foreach $key(@sorted_key) {
    print "$key:$hash{$key}\n";
}



実行結果


c:5
e:4
b:3
d:2
a:1



日本語を処理する

日本語を処理するには、使用する文字コードを指定します。

use utf8; # 日本語(UTF8)を使用する

binmode STDIN, "utf8"; # 標準入力に日本語(UTF8)を使用する
binmode STDOUT, "utf8"; # 標準出力に日本語(UTF8)を使用する



サブルーチンの引数にファイルハンドルと配列を渡す

サブルーチンにファイルハンドルと配列を渡すには、以下のようにします。


open(my $OUT, ">", $ARGV[0]);

my @array = ('TEST1', 'TEST2', 'TEST3');

&out_array($OUT, @array);

close($OUT);


$ARGV[0]は上記プログラムを起動した時の最初の引数で、出力するファイル名を指定します。
$OUTはファイルハンドルを格納する変数です。
out_arrayはサブルーチン名で、引数に$OUTと配列@arrayを渡しています。

呼び出される側のサブルーチンは以下のようにして引数を取得できます。


sub out_array
{
    my $OUT = $_[0];
    my $item1 = $_[1];
    my $item2 = $_[2];
    my $item3 = $_[3];

    print $OUT "$item1\t$item2\t$item3\n"; # 指定された出力ファイルに"TEST1¥tTEST2¥tTEST3¥nと出力されます。
}





定数

Perlで定数を使用する時は、use constantを使用します。

use constant DATA => 0;
print DATA; # 0と出力されます


定数には文字列も指定可能です。

use constant DATA => 'TEST';
print DATA; # TESTと表示されます


defined

標準入力等から1行読み込む場合、<STDIN>とかを使いますが、
これ以上読み込む行が存在しない場合やファイルの最後の場合、undefが返ってきます。
入ってきた1行が存在しないか、最後かを判定する為にdefinedで判定します。

$line = <STDIN>;
if (!defined ($line)) {
   # 最後
}

undef

未初期化データの値はundefになります。
数値がundefの場合0として振る舞い、文字列がundefの場合は''(空文字)として振る舞います。

ディレクトリの存在チェックと作成

ディレクトリの存在チェック
if (!-d $dirpath)

ディレクトリの作成
mkdir $dirpath;

配列の要素数

配列の最後のインデックス
$#array;

配列の要素数
scalar(@array);

Perlの名前

Perlとは一応、Practical Extraction and Report Language(実用データ取得レポート作成言語)の略だそうです。

でも、Perl言語を作った作者Larry Wall氏によれば、最初にPerlという名前に決め、後で上の様なそれらしい名前を当てはめたんだそうです。

ですので、あくまでも1行目の名前は一説であり、Pathologically Eclectic Rubbish Lister(病的折衷主義のがらくた出力機)という説もあるんだそうです。ニヤリ。

はじめてのPerl

オライリー社から出版されている「はじめてのPerl」(通称リャマ本)に基づいてPerl言語を学習していくブログです。

よろしくお願いします。