String オブジェクトを破壊的に空文字列化(2)
http://d.hatena.ne.jp/sa-y/20051221#1135158425 の続き.
他に思い付かなかったのでとりあえず benchmark.rb してみる.
以下の4つの処理を試しました.
- str.replace('')
- str.slice!(0..-1)
- str[0..-1] = ''
- str.sub!(/.*/, '')
コードは以下の通りです.
require 'benchmark' NUMBER_OF_STRING = 200000 def create_data_array(string_length) original_string = '0' * string_length data_array = [] NUMBER_OF_STRING.times(){ |i| data_array << original_string.dup } data_array end Benchmark::bm(25){ |x| [10, 100, 1000, 2000].each(){ |length| puts "----- String#length : #{length}" GC.start() data_array = create_data_array(length) x.report("str.replace('')") { data_array.each(){ |str| str.replace('') } } GC.start() data_array = create_data_array(length) x.report("str.slice!(0..-1)") { data_array.each(){ |str| str.slice!(0..-1) } } GC.start() data_array = create_data_array(length) x.report("str[0..-1] = ''") { data_array.each(){ |str| str[0..-1] = '' } } GC.start() data_array = create_data_array(length) regexp = Regexp::compile('.*') x.report("str.sub!(/.*/, '')") { data_array.each(){ |str| str.sub!(regexp, '') } } } }
実行結果は以下の通り.
user system total real ----- String#length : 10 str.replace('') 0.410000 0.030000 0.440000 ( 0.441957) str.slice!(0..-1) 0.610000 0.020000 0.630000 ( 0.624024) str[0..-1] = '' 0.350000 0.020000 0.370000 ( 0.364398) str.sub!(/.*/, '') 0.570000 0.010000 0.580000 ( 0.579559) ----- String#length : 100 str.replace('') 0.330000 0.050000 0.380000 ( 0.381891) str.slice!(0..-1) 0.680000 0.070000 0.750000 ( 0.746998) str[0..-1] = '' 0.360000 0.060000 0.420000 ( 0.418298) str.sub!(/.*/, '') 1.000000 0.040000 1.040000 ( 1.043050) ----- String#length : 1000 str.replace('') 0.380000 0.020000 0.400000 ( 0.395453) str.slice!(0..-1) 1.390000 0.040000 1.430000 ( 1.430818) str[0..-1] = '' 0.420000 0.010000 0.430000 ( 0.425488) str.sub!(/.*/, '') 35.990000 0.100000 36.090000 ( 36.095320) ----- String#length : 2000 str.replace('') 0.380000 0.020000 0.400000 ( 0.401155) str.slice!(0..-1) 2.110000 0.070000 2.180000 ( 2.179827) str[0..-1] = '' 0.370000 0.060000 0.430000 ( 0.432991) str.sub!(/.*/, '') 75.550000 0.220000 75.770000 ( 75.787502)
ずいぶんと誤差がありそうな気がするけど大体の傾向はつかめます.
1. 3. の方法は文字列の長さに影響されない、または無視できる範囲の影響しかなさそう.2. 4. はレシーバの長さが長いほど処理時間が長くなる模様.
str.sub!(/.*/, '') が遅いのは予想通りですが str.slice!(0..-1) も遅くなるのですねぇ…. あ… String#slice!() は取り除いた部分文字列を返す,という仕様だからですか.毎回元の文字列と同じ内容の String オブジェクトを生成するから遅くなるのですね.
とりあえずの結論はこんな感じですか…
class String unless method_defined?(:clear) then def clear() replace('') end end end