「Ruby」カテゴリーアーカイブ

多次元配列

Rubyでは基本的に配列は一次元。多次元配列を定義する方法はいつくかあるようだが、その中の一つ。

da=Array.new(3).map!{Array.new}

配列の初期化ついては注意が必要。

da=Array.new(3,Array.new(4,0))

のようにnewの引数に初期値を与えると、3個の配列がすべて同じオブジェクトになってしまう。

da[0][1]=7
p da #=> [[0,7,0,0],[0,7,0,0],[0,7,0,0]]
da=Array.new(3).map!{Array.new(4){0}}

のようにブロックを使用すれば大丈夫。

*確認したところ、

da=Array.new(3).map!{Array.new(4,0)}

でも問題なかったが、ブロック文の方が安全か。
一次元配列でさらに確認してみると、

ary=Array.new(3,"foo")
ary[0].capitalize! 
p ary #=>gt;["Foo", "Foo", "Foo"]

とすべての要素が化けてしまうが、最後が破壊的メソッドでなく

ary[0]=ary[0].capitalize

のように代入してしえば一つの要素だけを変更できる。
とりあえず、配列の取扱いは代入を基本としている限りは大丈夫そうだが
念のためブロックを使って初期化するに越したことはない。

空白の消去

元素記号は一文字のもの(H,Oなど)と二文字(Ptとか)のものがあるため、固定長レコードで処理しようとすると2バイト分確保しておく必要がある。そうすると、一文字のものについてはunpackしたときに余分な空白がついてしまう。strip methodで空白を落とせるが、少し煩雑な気がしなくもない。

    buf = rec.unpack("a2")
    printf("%3s\n",buf[0].strip)

バイナリデータの読み書き

open methodの第2変数にbを追加すると、”バイナリモード(ここでの「バイナリ」は改行方式を指すのみであって、取り扱うデータ自体がバイナリかそうでないかは特に関係がない)”で書き込みが行われる。

bin = open("test.bin", "wb")

pack methodで配列中のデータを変換する。下は、配列barの中身を2バイトの文字列と8バイトの倍精度実数x3、計26バイトの固定長に変換する。4バイトの単精度実数にしたい場合は、d→fと変更すればよい。

bin.print(bar.pack("a2d3"))

生成したファイルの容量が、きっかり26バイトになっているのにはちょっと感動。Fortranだと、単にwrite, readするだけでデータ長はほとんど意識しないので。読み取りにはunpackメソッドを用いる。

bin = open("test.bin", "rb")
while rec = bin.read(26)
 buf = rec.unpack("a2d3")
end

さらに、seek methodでデータ読み取り(書き込みも)の開始位置を指定できる。
一行のデータがrecバイトのとき、

 bin.seek(n*rec)

でn行読み飛ばし、

bin.read(rec)

でn+1行目から読んでいくことができる。これは便利。