Perlの小技をまとめておきます。
grep
を使えばできます。
しかし、配列の要素数が多いときは時間がかかるので、おすすめできません。
@a1 = ( 1, 3, 5, 7 ); @a2 = ( 2, 4, 6, 8 ); if( grep( $_==3, @a1 )>0 ){ print "3 is in \@a1\n"; }else{ print "3 is not in \@a1\n"; } if( grep( $_==3, @a2 )>0 ){ print "3 is in \@a2\n"; }else{ print "3 is not in \@a2\n"; }
3 is in @a1 3 is not in @a2
配列の各要素に、配列への参照を代入すれば多次元配列ができあがり。
@a = ( [1,2,3], [4,5,6] ); print "(0,0):$a[0][0] (0,1):$a[0][1] (0,2):$a[0][2]\n"; print "(1,0):$a[1][0] (1,1):$a[1][1] (1,2):$a[1][2]\n";
(0,0):1 (0,1):2 (0,2):3 (1,0):4 (1,1):5 (1,2):6
@a = ( [[11,12], [21,22], [31,32]], [[41,42], [51,52], [61,62]] ); foreach $i ( 0..1 ){ foreach $j ( 0..2 ){ print "($i,$j,0):$a[$i][$j][0] ($i,$j,1):$a[$i][$j][1]\n"; }}
(0,0,0):11 (0,0,1):12 (0,1,0):21 (0,1,1):22 (0,2,0):31 (0,2,1):32 (1,0,0):41 (1,0,1):42 (1,1,0):51 (1,1,1):52 (1,2,0):61 (1,2,1):62
多次元配列の要素となっている配列を取り出すには、
下のように @{〜}
とすればよい。
@a = ( [1,2,3], [4,5,6] ); # 第2成分のみをコピー @b = @{$a[1]}; # 第2成分の配列全体。 print "\@b = ( $b[0], $b[1], $b[2] )\n"; # 2次元配列 foreach ループでを表示 print "\@a =\n"; foreach ( @a ){ print "( @$_ )\n"; }
@b = ( 4, 5, 6 ) @a = ( 1 2 3 ) ( 4 5 6 )
@b=@a
だとうまくいかないので要注意.
次のような関数でコピーできます.
sub copy_array_of_arrays(\@\@\@){ my ( $orig, $copy ) = @_; @{$copy} = (); foreach ( @{$orig} ){ push( @{$copy}, [ @$_ ] ); } } @a = ( [1,3,5], [2,4,6,8] ); ©_array_of_arrays(\@a,\@b); # @a を @b にコピー.@b の要素を変更しても @a の要素は変わりません. print "\@a="; foreach ( @a ){ print "( @$_ ) "; } print "\n"; print "\@b="; foreach ( @b ){ print "( @$_ ) "; } print "\n\n"; $b[0][2]=7; print "\@a="; foreach ( @a ){ print "( @$_ ) "; } print "\n"; print "\@b="; foreach ( @b ){ print "( @$_ ) "; } print "\n\n"; # 失敗例:@a を @c にコピー.@c の要素を変更すると @a の要素も変わってしまう... @c=@a; print "\@a="; foreach ( @a ){ print "( @$_ ) "; } print "\n"; print "\@c="; foreach ( @c ){ print "( @$_ ) "; } print "\n\n"; $c[0][2]=7; print "\@a="; foreach ( @a ){ print "( @$_ ) "; } print "\n"; print "\@c="; foreach ( @c ){ print "( @$_ ) "; } print "\n";
@a=( 1 3 5 ) ( 2 4 6 8 ) @b=( 1 3 5 ) ( 2 4 6 8 ) @a=( 1 3 5 ) ( 2 4 6 8 ) @b=( 1 3 7 ) ( 2 4 6 8 ) @a=( 1 3 5 ) ( 2 4 6 8 ) @c=( 1 3 5 ) ( 2 4 6 8 ) @a=( 1 3 7 ) ( 2 4 6 8 ) @c=( 1 3 7 ) ( 2 4 6 8 )
2つの2次元配列をつなげて,あらたに2次元配列を作る関数.
sub join_array_of_arrays(\@\@\@){ my ( $orig1, $orig2, $result ) = @_; @{$result} = (); foreach ( @{$orig1} ){ push( @{$result}, [ @$_ ] ); } foreach ( @{$orig2} ){ push( @{$result}, [ @$_ ] ); } } @a = ( [1,3,5], [2,4,6] ); @b = ( [9,7], [8,6] ); &join_array_of_arrays(\@a,\@b,\@c); foreach ( @c ){ print "( @$_ )\n"; }
( 1 3 5 ) ( 2 4 6 ) ( 9 7 ) ( 8 6 )
2次元配列の最後に,(1次元)配列を追加するには,
[ @〜 ]
を push
すればよいです。
@a = ( [1,3,5], [2,4,6] ); @c=(9,7); push( @a, [ @c ] ); foreach ( @a ){ print "( @$_ )\n"; }
( 1 3 5 ) ( 2 4 6 ) ( 9 7 )
MatrixRealパッケージを使って、Perlで行列計算を行う方法をまとめておきます。 MatrixReal Version:1.9について記述しています. 最新版で動くかどうかは未確認です.ソースファイルなどへのリンクは1.9のままです.古いです. 行列の乗算・逆行列・転置行列・行列式・トレース・実対称行列の対角化 などいろいろできます。 詳しくは、 マニュアルを参照。
MatrixReal.pm をダウンロードして、
/usr/lib/perl5/Math/ っぽい名前のディレクトリの下に
保存すれば使えるようになります。
ActivePerl では,「スタートメニュー」→「Active Perl」→「Perl Package Manager」を
実行(もしくはコマンドプロンプトからppm を実行)すれば,GUI画面でインストールできると思われます。便利です。
ソースファイルの先頭あたりに以下を書いておく。
use Math::MatrixReal;
べたっと書くのが最も簡単。
use Math::MatrixReal; $mat = Math::MatrixReal->new_from_string(<<'MATRIX'); [ 2 -1 ] [ -3 2 ] MATRIX print "$mat";
[ 2.000000000000E+000 -1.000000000000E+000 ] [ -3.000000000000E+000 2.000000000000E+000 ]
2次元配列への参照を渡して定義することも可能。
use Math::MatrixReal; @array = ( [2,-1], [-3, 2] ); # 2次元配列を定義 $mat = Math::MatrixReal->new_from_rows(\@array); print "$mat";
[ 2.000000000000E+000 -1.000000000000E+000 ] [ -3.000000000000E+000 2.000000000000E+000 ]
n
行m
列の0行列は、
new Math::MatrixReal(n,m)
とすればできる。
use Math::MatrixReal; $mat = new Math::MatrixReal(2,3); print "$mat";
[ 0.000000000000E+000 0.000000000000E+000 0.000000000000E+000 ] [ 0.000000000000E+000 0.000000000000E+000 0.000000000000E+000 ]
行列の各要素を表す関数を使っても定義できる。
use Math::MatrixReal; $mat = new Math::MatrixReal(3,3); $mat = $mat->each ( sub { my( $x,$i,$j)=@_; $i+2*$j } ); print "$mat";
[ 3.000000000000E+000 5.000000000000E+000 7.000000000000E+000 ] [ 4.000000000000E+000 6.000000000000E+000 8.000000000000E+000 ] [ 5.000000000000E+000 7.000000000000E+000 9.000000000000E+000 ]
$mat->dim()
とすれば、
$mat
の (行数, 列数) が返ってくる。
$mat->element(i,j)
とすれば、
$mat
の (i,j)
-要素の値が返ってくる。
use Math::MatrixReal; $mat = Math::MatrixReal->new_from_string(<<'MATRIX'); [ -1 2 3 ] [ -4 -5 -6 ] MATRIX ($d1,$d2)= $mat->dim(); # 行列の次元数を取得 $x = $mat->element(2,1); # 2行1列の要素を取得 print "$d1 rows, $d2 columns, (2,1)-element is $x\n";
2 rows, 3 columns, (2,1)-element is -4
$mat->assign(i,j,x)
とすれば、
$mat
の (i,j)
-要素を x
に変更できる。
use Math::MatrixReal; $mat = Math::MatrixReal->new_from_string(<<'MATRIX'); [ -1 2 3 ] [ -4 -5 -6 ] MATRIX $mat->assign(2,1,7); # 2行1列の要素を7に変える。 print "$mat";
[ -1.000000000000E+000 2.000000000000E+000 3.000000000000E+000 ] [ 7.000000000000E+000 -5.000000000000E+000 -6.000000000000E+000 ]
普通の数字の演算と同じく、
+, -, *, **
などが使える。
use Math::MatrixReal; $mat1 = Math::MatrixReal->new_from_string(<<'MATRIX'); [ 2 -1 ] [ -3 2 ] MATRIX $mat2 = Math::MatrixReal->new_from_string(<<'MATRIX'); [ -2 0 ] [ 1 1 ] MATRIX $mat = $mat1 + $mat2; print "$mat\n"; # 足し算 $mat = $mat1 - $mat2; print "$mat\n"; # 引き算 $mat = $mat1 * $mat2; print "$mat\n"; # 掛け算 $mat = $mat1 * 3; print "$mat\n"; # 定数倍 $mat = $mat1 ** 3; print "$mat\n"; # 行列のべき乗
$mat->inverse()
とすれば、
$mat
の逆行列が返ってくる。
逆行列がない場合は、undef
が返ってくる。
use Math::MatrixReal; $mat = Math::MatrixReal->new_from_string(<<'MATRIX'); [ 2 -1 ] [ -3 2 ] MATRIX if( $inv = $mat->inverse() ){ print "$inv"; }else{ print "No inverse matrix.\n"; }
[ 2.000000000000E+000 1.000000000000E+000 ] [ 3.000000000000E+000 2.000000000000E+000 ]
$mat2->trans($mat1)
とすれば、
$mat2
に $mat1
の転置行列が代入される。
ただし、$mat2
は、あらかじめしかるべきサイズの
行列として定義されている必要がある。
use Math::MatrixReal; $mat1 = Math::MatrixReal->new_from_string(<<'MATRIX'); [ -1 2 3 ] [ -4 -5 -6 ] MATRIX $mat2 = new Math::MatrixReal( reverse $mat1->dim() ); $mat2->transpose($mat1); print "$mat2";
[ -1.000000000000E+000 -4.000000000000E+000 ] [ 2.000000000000E+000 -5.000000000000E+000 ] [ 3.000000000000E+000 -6.000000000000E+000 ]
$mat->det(), $mat->trans()
で、
$mat
の行列式, 対角和(トレース)が返ってくる。
use Math::MatrixReal; $mat = Math::MatrixReal->new_from_string(<<'MATRIX'); [ 2 -1 ] [ -3 2 ] MATRIX $x = $mat->det(); print "determinant: $x\n"; # 行列式 $x = $mat->trace(); print "trace : $x\n"; # 対角成分の和
determinant: 1 trace : 4