理科系の勉強日記

Linux/Ubuntu/Mac/Emacs/Computer vision/Robotics

Perlの2次元配列メモ

Perlで二次元配列を動的に生成する場合を考える.

for( $i=0; $i<200; $i++){
   for ($j=0; $j<@data1; $j++) {
	$data2[$i][$j] = $data1[$j];    
    }
}

このように書くだけで,動的に二次元配列とすることができる.ここで

$j<@data1

は,@data1の要素数だけループを回している.

配列の要素数を取り出すときは以下のようにすればよい.

scalar(@data1);
@data1+0;

いずれも同じ結果を返す.


2次元配列の場合は

# data2[][]の1つ目の[]の長さ
scalar(@data2);
@data2+0;

# data2[][]の2つ目の[]の長さ
scalar(@{$data2[0]});
@{$data2[0]}+0;

とすればよい.

stdout: Broken pipe

gnuplot> plot "<cat vec.dat | head -23" using 3 with line

vec.datは30万行を超えるデータである.catの結果をパイプでheadに渡すと

cat: stdout: Broken pipe

などと仰った.パイプが壊れたようだ.

これはcatの結果が30万行と膨大で,その結果が終わるまでにheadを読み込んでいるためと思われる.そもそもcatの後にhaedをする必要は無い.正しくは

gnuplot> plot "<head -23 vdc.dat" using 3 with line

でよい.

gnuplotでplot for

gnuplotでは,複数個のグラフをfor文を用いてplotすることができる.

例えば,手元に連番ファイル「00.dat, 01.dat, ... , 09.dat」があったとする.for文を使わない場合は

plot  "00.dat" u 1:2 with lp title "data 00"
replot "00.dat" u 1:2 with lp title "data 01"
...
replot "09.dat" u 1:2 with lp title "data 09"

などとなる.

plot forを使う場合は以下のようになる.

plot for [i=0:9] sprintf( "%02d.dat", i ) using 1:2 with lp title sprint("data %02d", i )  

「sprintf("----")」が「"----"」に置き換わるので,規則性をもつファイル名に対して大変便利である.

メモ

他の機能と組み合わせて

plot for [i=0:10] sprintf( "<head -%d output.dat |tail -8", (i+1)*8 ) using 2 with lp notitle

というように使用した.

シェルで行列を転置

以下の様なデータ(data.txt)をシェルで転置する.

0 615276 615276 615276 615276 615276 615276 615276 615276
0.1 580455 587213 587232 589734 590158 591019 592493 596381
0.2 500342 522058 521903 530142 531954 534774 539629 552938
0.3 426424 458656 458049 470653 474194 478489 485944 507184
0.4 375159 411233 410162 424713 429627 434569 443225 468618
0.5 342701 378289 376901 391707 397429 402447 411317 437847
0.6 322694 355534 353990 368090 374123 378893 387403 413158
0.7 310526 339517 337952 350821 356785 361137 368960 392786
0.8 303315 327889 326402 337732 343347 347183 354112 375272
0.9 299324 318961 317638 327164 332195 335441 341278 359132

ワンライナーで以下のように書いた.

N=$(head -n 1 data.txt | wc -w);for i in `seq 1 $N`;do awk '{print $'$i'}' < data.txt | tr '\n' '\t' ; echo;done
0	0.1	0.2	0.3	0.4	0.5	0.6	0.7	0.8	0.9	
615276	580455	500342	426424	375159	342701	322694	310526	303315	299324	
615276	587213	522058	458656	411233	378289	355534	339517	327889	318961	
615276	587232	521903	458049	410162	376901	353990	337952	326402	317638	
615276	589734	530142	470653	424713	391707	368090	350821	337732	327164	
615276	590158	531954	474194	429627	397429	374123	356785	343347	332195	
615276	591019	534774	478489	434569	402447	378893	361137	347183	335441	
615276	592493	539629	485944	443225	411317	387403	368960	354112	341278	
615276	596381	552938	507184	468618	437847	413158	392786	375272	359132	

まず、data.txtの列数を数える。headで一行だけ取ってきて、そのデータ数をカウントする。
この結果をNに格納し、各列に対してawkを実行する。awkでは、改行(\n)をタブ(\t)に変換している。

もっとシンプルなコマンドやoctavematlabといったソフトウェアを使うという方法もあると思うが,まあ動けば何でもよいということで.


# 訂正 2016.11.19
doの後に";"があってコマンドが通らなかったため、訂正
ファイル名が全部違っていたので、訂正

ご指摘ありがとうございました。

連番のファイル名を変換する

連番画像のファイル名を一気に変えるコマンド.
lsで表示したものに番号を振り,それを入力としてawkでコマンドを形成,shで実行する.

ls *ppm | cat -n | awk '{printf "cp %s img_%04d.ppm\n", $2, $1}' | sh

shをevalにすると上手くいかない.
(shだと毎行実行してくれる)