>> 古い記事: Javascript: オブジェクトからコンストラクタ名(クラス名)を得る
<< 新しい記事: 2010-02: MinGW(インストーラ不使用)で Ruby 1.8.7 をビルドする

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Ruby 1.8.7 でファイルの行数カウント

String#count で改行を数える方法は、 (おそらく)一旦全部読み込むので大きなファイルだとメモリの制約を受ける。 簡単に調べた限りではこの方法は wc -l の出力と同じ。

File#lineno を使う場合は逐次処理なので大きなファイルでも大丈夫。

ファイル数が少ない場合は wc が早いが、 小さなファイルをたくさん調べたい場合は Ruby で読んだ方が速い。


require "benchmark"

def lineno_a(path)
  open(path).each{}.lineno
end

def lineno_b(path)
  open(path).read.count("\n")
end

def lineno_wc(path)
  `wc -l #{path}`.to_i
end


def test_lineno(str)
  path = "temp.txt"
  open(path, "w"){|f| f.print str }
  puts "%d, %d, %d" % [ lineno_a(path), lineno_b(path), lineno_wc(path) ]
end

def test_lineno_speed(col, row, t)
  path = "temp.txt"
  open(path, "w"){|f|
    row.times{
      f.puts "x" * col
    }
  }

  Benchmark.bmbm {|x|
    x.report("a :" ) { t.times { lineno_a(path) } }
    x.report("b :" ) { t.times { lineno_b(path) } }
    x.report("wc:") { t.times { lineno_wc(path) } }
  }
end

                      #   a  b  wc
test_lineno( ""     ) #=> 0, 0, 0
test_lineno( "-"    ) #=> 1, 0, 0
test_lineno( "\n"   ) #=> 1, 1, 1
test_lineno( "-\n"  ) #=> 1, 1, 1
test_lineno( "\n-"  ) #=> 2, 1, 1
test_lineno( "-\n-" ) #=> 2, 1, 1

puts "--------------------------------"
test_lineno_speed(100, 100000, 10)
test_lineno_speed(100, 10000, 100)
test_lineno_speed(100, 1000, 1000)
# test_lineno_speed(100, 100, 10000) #=> wc がすごく遅い

puts "--------------------------------"
test_lineno_speed(10,  10000000, 1)
test_lineno_speed(1000,  100000, 1)
test_lineno_speed(100000,  1000, 1)
test_lineno_speed(10000000,  10, 1)

↓ベンチマーク部分の結果(Rehearsal部分は省略)

          user     system      total        real
a :   0.400000   0.040000   0.440000 (  0.486992)
b :   0.170000   0.100000   0.270000 (  0.300630)
wc:   0.000000   0.000000   0.100000 (  0.114541)

          user     system      total        real
a :   0.420000   0.040000   0.460000 (  0.530831)
b :   0.150000   0.100000   0.250000 (  0.270326)
wc:   0.000000   0.000000   0.210000 (  0.237720)

          user     system      total        real
a :   0.420000   0.040000   0.460000 (  0.477285)
b :   0.110000   0.070000   0.180000 (  0.170948)
wc:   0.030000   0.090000   1.550000 (  1.713370)

--------------------------------

          user     system      total        real
a :   3.450000   0.030000   3.480000 (  3.593668)
b :   0.150000   0.120000   0.270000 (  0.266693)
wc:   0.000000   0.000000   0.150000 (  0.150003)

          user     system      total        real
a :   0.120000   0.030000   0.150000 (  0.153653)
b :   0.140000   0.090000   0.230000 (  0.235965)
wc:   0.000000   0.000000   0.070000 (  0.071196)

          user     system      total        real
a :   0.080000   0.060000   0.140000 (  0.136595)
b :   0.120000   0.100000   0.220000 (  0.229562)
wc:   0.000000   0.000000   0.070000 (  0.072572)

          user     system      total        real
a :   0.080000   1.620000   1.700000 (  1.751896)
b :   0.160000   0.070000   0.230000 (  0.226595)
wc:   0.000000   0.000000   0.060000 (  0.062554)

得られる行数に厳密さが求められず、大まかでよい場合は次のようにしてもいいかも。 (実際どうなるかは調べてないです)


lineno = begin
           open(path).read.count("\n")
         rescue NoMemoryError
           open(path).each{}.lineno
         end

環境

Ubuntu Linux 9.04 32bit
ruby 1.8.7 (2008-08-11 patchlevel 72) [i486-linux]

参考(外部リンク)

>> 古い記事: Javascript: オブジェクトからコンストラクタ名(クラス名)を得る
<< 新しい記事: 2010-02: MinGW(インストーラ不使用)で Ruby 1.8.7 をビルドする
** ホームに戻る

コメント

コメントの投稿

管理者にだけ表示を許可する

|
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。