6

文字列が与えられた場合、文字列内の改行の先頭の文字位置の配列を返す最も効率的な方法は何ですか?

text =<<_
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in 
culpa qui officia deserunt mollit anim id est laborum.
_

期待される:

find_newlines(text) # => [0, 80, 155, 233, 313, 393]

私自身の回答を投稿します。受け入れられた答えとして最速の方法を受け入れたいと思います。


ここのベンチマーク結果は、新しい回答が追加されると更新されます

require "fruity"

compare do
  padde1 {find_newlines_padde1(text)}
  digitalross1 {find_newlines_digitalross1(text)}
  sawa1 {find_newlines1(text)}
  sawa2 {find_newlines2(text)}
end

# Running each test 512 times. Test will take about 1 second.
# digitalross1 is faster than sawa2 by 5x ± 0.1
# sawa2 is faster than sawa1 by 21.999999999999996% ± 1.0%
# sawa1 is faster than padde1 by 4.0000000000000036% ± 1.0%
4

3 に答える 3

3
def find_newlines text
  s = 0
  [0] + text.to_a[0..-2].map { |e| s += e.size }
end

前述のように、text.each_line.to_a1.9 に使用します。1.8.7 では呼び出しeach_lineも機能しますが、呼び出しのみより 20% 遅くなりますto_a.

于 2013-02-18T19:05:20.660 に答える
2

あなたの答えに似ています:

def find_newlines_padde1 text
  text.enum_for(:scan, /^/).map do
    $~.begin(0)
  end
end

rubyinlineを使用すると、ある程度のパフォーマンスを得ることができます:

require "inline"
module Kernel
  inline :C do |builder|
    builder.add_compile_flags '-std=c99'
    builder.c %q{
      static VALUE find_newlines_padde2(VALUE str) {
        char newline = '\n';
        char* s = RSTRING_PTR(str);
        VALUE res = rb_ary_new();
        str = StringValue(str);
        rb_ary_push(res, LONG2FIX(0));
        for (long pos=0; pos<RSTRING_LEN(str)-1; pos++) {
          if (s[pos] == newline) {
             rb_ary_push(res, LONG2FIX(pos+1));
          }
        }
        return res;
      }
    }
  end
end

pos<RSTRING_LEN(str)-1あなたが要求したのと同じ結果を得るために、人為的に早期に終了していることに注意してください。必要に応じてこれを変更できるpos<RSTRING_LEN(str)ので、最後の空行も行頭としてカウントされます。あなたはどちらがあなたのために働くかを決めるでしょう.

フルーティー 言うpadde2 is faster than sawa2 by 22x ± 0.1

于 2013-02-18T17:25:03.507 に答える
0
def find_newlines_sawa1 s
  a = []
  s.scan(/^/){a.push($~.offset(0)[0])}
  a
end

find_newlines_sawa1(text) # => [0, 80, 155, 233, 313, 393]

def find_newlines_sawa2 s
  a = [0]
  s.split(/^/).each{|s| a.push(a.last + s.length)}
  a.pop
  a
end

find_newlines_sawa2(text) # => [0, 80, 155, 233, 313, 393]
于 2013-02-18T16:40:00.677 に答える