重要なお知らせ

「教えて! goo」は2025年9月17日(水)をもちまして、サービスを終了いたします。詳細はこちら>

【GOLF me!】初月無料お試し

お世話になります。
rubyを用いたx行からy行までの抜き出しについて教えて頂きたいです。
現在、
test1.inp
というファイルがあり、そのtest1.inpを
指定列から106577行ずつ切り出したファイルを作りたいと思い、
ruby -e 'puts ARGF.read.split("\n")[211579..318156]' test1.inp > data1.txt
ruby -e 'puts ARGF.read.split("\n")[423162..529739]' test1.inp > data2.txt
ruby -e 'puts ARGF.read.split("\n")[634745..741322]' test1.inp > data3.txt
ruby -e 'puts ARGF.read.split("\n")[846328..952905]' test1.inp > data4.txt
ruby -e 'puts ARGF.read.split("\n")[1057911..1164488]' test1.inp > data5.txt
(以下まだまだ続く。)
というワンライナー構文を書いて切り出しをしております。
どういうことかというと
211580行目から318157行目までをdata1.txtというファイルで書き出せ。(rubyは1行目を0行目とするのでプログラム上での数字は-1行されています。)
423163行目から529739行目までをdata2.txtとして書き出せ。
という構文であります。
上記のように、ワンライナーですと、ファイルを切り出するたびにtest1.inpという親ファイルを閉じてしまうために、test1.inpファイルのサイズが大きい場合には非常に時間がかかってしまうという欠点が出ています。
そこで、test1.inpファイルを毎回毎回開いては閉じてという工程をさせないようにさせる、
つまりdata1.txtやdata2.txtを高速で出力させる方法がわかる方がお見えでしたら是非ともこの方法を教えてください。
よろしくお願いします。

質問者からの補足コメント

  • うれしい

    実行してみました。
    ものすごく速いですね。いままでのワンライナー構文の100倍以上の速度出ます。
    rubyでは開始行数、StartLine = 211580 #出力開始行
    のところをマイナス1行して211579にしてやらなければならないと思っていたのですが、マイナス1しなくても良いのですね。puts ARGF.readなどARGFを使う時だけマイナス1しなければならないのでしょうか?

    No.1の回答に寄せられた補足コメントです。 補足日時:2018/07/24 15:54

A 回答 (2件)

データがあれば、延々とdata1.txt・・・・dataN.txtを作成し続けます。


以下のスクリプトを実行してください。
ruby スクリプト名 test1.inp のように入力します。
---------------------------------------------------------
# coding:WINDOWS-31J
StartLine = 211580 #出力開始行
Span = 211583 #出力間隔(次の出力開始行までの間隔)
Band = 106577 #出力範囲(出力開始行から何行出力するかの範囲)
ls = StartLine
le = ls + Band
ofp = nil
fno = 1
lno = 0
File.open(ARGV[0]) do |file|
while line = file.gets
lno += 1
#読み込んだ行が開始行~終了行の範囲内なら、以下の処理を行う
if lno >= ls && lno <= le
#開始行の場合、出力ファイルをオープンする
if lno == ls
ofp = File.open("data" + fno.to_s + ".txt","w")
end
#1行出力
ofp.print line
#終了行に達した場合、出力ファイルをクローズし、次の出力に備える
if lno == le
ofp.close
ofp = nil
fno += 1
ls += Span
le = ls + Band
end
end
end
end
#途中で終わった場合、出力ファイルをクローズ
if ofp != nil
ofp.close
end
この回答への補足あり
    • good
    • 0
この回答へのお礼

tatsu99さま
今回もお答えいただき感謝いたします。
明日、実験室に行ったら早速実行してみます。
まずはお礼まで。

お礼日時:2018/07/23 22:36

>puts ARGF.readなどARGFを使う時だけマイナス1しなければならないのでしょうか?


いいえ。今回のあなたが作成されたワンライナーの構文の為です。
ワンライナーで記述された以下のスクリプトは、
ruby -e 'puts ARGF.read.split("\n")[211579..318156]' test1.inp > data1.txt
下記のような処理になります。
1. test1.inpを内部メモリに全て読み込み・・・・ファイルサイズ分のメモリが必要
2. 内部メモリに読み込んだ文字列を\nで分割し、配列に格納・・・・更に、ほぼ同じサイズのメモリが必要
3.上記の配列の文字列[211579]~文字列[318156]を出力

上記の1行目のデータは文字列[0]になります。文字列[211579]とは211580行目のデータです。
マイナス1するのは、1行毎に配列に格納している為です。(配列の添え字は0から始まります)
ARGFをつかっている為ではありません。

尚、実行速度ですが、上記の1と2でおよそファイルサイズ×2のメモリを必要としています。
今回はファイルサイズが大きいため、その影響で、遅くなっていると考えられます。(推測ですが)
    • good
    • 0
この回答へのお礼

ようやく納得できました。
全てメモリに格納してからさらに分割ですメモリ使うという処理を繰り返すとか、とんでもない負荷をPCにかけてたような…(汗
ありがとうございました。

お礼日時:2018/07/24 16:36

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!