Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

Ruby文字列のクリーンアップが13倍速く

考えをコードに変換するときは、ほとんどの場合、最もよく知っている方法を使用します。これらは頭に浮かぶ方法であり、自動的に表示されます。クリーンアップが必要な文字列が表示され、結果を得る方法を指で入力します。

多くの場合、自動的に入力するメソッドは、最も一般的なRubyメソッドです。これは、他のメソッドよりも読み取りと書き込みが多いためです。 #gsub 文字列内の文字を置き換える一般的な方法です。しかし、Rubyにはさらに多くの機能があり、標準的な操作のためのより専門的な便利な方法があります。

私はRubyの豊富なイディオムが大好きです。それは、コードがよりエレガントで読みやすくなるからです。この豊富さの恩恵を受けたい場合は、コードの最も単純な部分(文字列のクリーンアップなど)でもリファクタリングに時間を費やす必要があり、語彙を拡張するには少し手間がかかります。問題は、余分な努力はそれだけの価値があるのか​​ということです。

スペースを削除する4つの方法

クレジットカード番号を表す文字列は次のとおりです:"055444285"。それを操作するには、スペースを削除します。 #gsub これを行うことができます。 #gsubを使用 何でもすべてに置き換えることができます。しかし、他のオプションがあります。

string = "055 444 285"
string.gsub(/ /, '')
string.gsub(' ', '')
string.tr(' ', '')
string.delete(' ')
 
# => "055444285"

便利な方法で一番好きな表現力です。最後のものはこれの良い例です:それは「スペースを削除する」より明白になりません。オプション間のトレードオフを考えると、もちろんパフォーマンスの問題が発生しない限り、読みやすさが私の最優先事項です。それでは、私のお気に入りのソリューションである#deleteがどれほど苦痛か見てみましょう。 本当に原因です。

上記の例をベンチマークしました。これらの方法のどれが最速だと思いますか?

Benchmark.ips do |x|
  x.config(time: 30, warmup: 2)
 
  x.report('gsub')           { string.gsub(/ /, '') }
  x.report('gsub, no regex') { string.gsub(' ', '') }
  x.report('tr')             { string.tr(' ','') }
  x.report('delete')         { string.delete(' ') }
 
  x.compare!
end
パフォーマンスの高いものから低いものへの順序を推測します。トグルを開いて結果を確認します
Comparison:
  delete:          2326817.5 i/s
  tr:              2121629.8 i/s   - 1.10x  slower
  gsub, no regex:  868184.1 i/s    - 2.68x  slower
  gsub:            474970.5 i/s    - 4.90x  slower

注文については驚きませんでしたが、速度の違いには驚きました。 #gsub 速度が遅いだけでなく、リーダーが引数を「デコード」するために余分な労力が必要になります。単なるスペース以上のものをクリーンアップするときに、この比較がどのように機能するかを見てみましょう。

番号を選んでください

次の電話番号を使用してください:'(408) 974-2414' 。数字だけが必要だとしましょう=>4089742414#scanを追加しました また、不要なものをすべて削除しようとするのではなく、特定の目的を目指していることをより明確に表現しているのが好きだからです。

Benchmark.ips do |x|
  x.config(time: 30, warmup: 2)
 
  x.report ('gsub')           { string.gsub(/[^0-9] /, '') }
  x.report('tr')              { string.tr("^0-9", "") }
  x.report('delete_chars')    { string.delete("^0-9") }
  x.report('scan')            { string.scan(/[0-9]/).join }
  x.compare!
end
もう一度、順序を推測し、トグルを開いて答えを確認します
Comparison:
  delete_chars:   2006750.8 i/s
  tr:             1856429.0 i/s   - 1.08x  slower
  gsub:           523174.7 i/s    - 3.84x  slower
  scan:           227717.4 i/s    - 8.81x  slower

正規表現を使用すると処理が遅くなりますが、これは驚くべきことではありません。そして、#scanの表現力を明らかにする意図 私たちに多大な費用がかかります。しかし、Rubyの特殊なメソッドがクリーンアップをどのように処理するかを見ると、もっと多くのことを味わうことができました。

お金について

部分文字列"€ "を削除するいくつかの方法を試してみましょう 文字列から"€ 300" 。次のソリューションのいくつかは、正確な部分文字列"€ "を指定します 、一部は単にすべての通貨記号またはすべての非数字を削除します。

Benchmark.ips do |x|
  x.config(time: 30, warmup: 2)
 
  x.report('delete specific chars')  { string.delete("€ ") }
  x.report('delete non-numericals')  { string.delete("^0-9") }
  x.report('delete prefix')          { string.delete_prefix("€ ") }
  x.report('delete prefix, strip')   { string.delete_prefix("€").strip }
 
  x.report('gsub')                   { string.gsub(/€ /, '') }
  x.report('gsub-non-nums')          { string.gsub(/[^0-9]/, '') }
  x.report('tr')                     { string.tr("€ ", "") }
  x.report('slice array')            { string.chars.slice(2..-1).join }
  x.report('split')                  { string.split.last }
  x.report('scan nums')              { string.scan(/\d/).join }
  x.compare!
end

勝者は#deleteの1つであると期待できます。 s。しかし、#deleteのどれか バリアントが最速になると思いますか?プラス:他の方法の1つは、いくつかの#deleteよりも高速です s。どれ?

推測してから開きます。
Comparison:
        delete prefix:   4236218.6 i/s
 delete prefix, strip:   3116439.6 i/s - 1.36x  slower
                split:   2139602.2 i/s - 1.98x  slower
delete non-numericals:   1949754.0 i/s - 2.17x  slower
delete specific chars:   1045651.9 i/s - 4.05x  slower
                   tr:   951352.0 i/s  - 4.45x  slower
          slice array:   681196.2 i/s  - 6.22x  slower
                 gsub:   548588.3 i/s  - 7.72x  slower
        gsub-non-nums:   489744.8 i/s  - 8.65x  slower
            scan nums:   418978.8 i/s  - 10.11x  slower

配列をスライスすることでさえ、#gsubよりも速いことに驚きました。 #splitの速さをいつも喜んでいます。 は。また、非数値をすべて削除する方が、特定の部分文字列を削除するよりも高速であることに注意してください。

お金を追いかける

番号の後の通貨を削除しましょう。 (遅い#gsubをスキップしました バリアント。)

Benchmark.ips do |x|
  x.config(time: 30, warmup: 2)
 
  x.report('gsub')                        { string.gsub(/ USD/, '')
  x.report('tr')                          { string.tr(" USD", "") }
  x.report('delete_chars')                { string.delete("^0-9")
  x.report('delete_suffix')               { string.delete_suffix(" USD") }
  x.report('to_i.to_s')                   { string.to_i.to_s }
  x.report("split")                       { string.split.first }
  x.compare!
end

勝者の間には引き分けがあります。最速を目指して競争するのはどれだと思いますか?

そして:ここに`#gsub`がどれだけ遅いかを推測します。
Comparison:
delete_suffix: 4354205.4 i/s
to_i.to_s: 4307614.6 i/s - same-ish: difference falls within error
split: 2870187.8 i/s - 1.52x slower
delete_chars: 1989566.1 i/s - 2.19x slower
tr: 1853957.1 i/s - 2.35x slower
gsub: 524080.6 i/s - 13.22x slower

ニーズに合った特別な方法が常にあるとは限りません。 #to_iは使用できません 先頭の「0」を維持する必要がある場合。そして#delete_suffix 通貨が米ドルであるという仮定に大きく依存しています。

特殊な方法は、特定のコンテキストでの特定のタスクに適した精密ツールのようなものです。したがって、#gsubが常に発生する場合があります まさに私たちが必要としているものです。それは用途が広く、常に頭の中にあります。しかし、処理が少し難しくなる可能性があり、多くの場合、予想よりも遅くなります。私にとって、Rubyの豊かさは、一緒に仕事をするのがとても楽しい理由の1つでもあります。スピードウィンは素晴らしいボーナスです。


  1. Ruby文字列のフォーマット

    Rubyで文字列をフォーマットする方法について話しましょう。 なぜ文字列をフォーマットしたいのですか?数値が10未満であっても、先行ゼロを使用したり(例:01、02、03…)、コンソール出力を列に適切にフォーマットしたりすることができます。 他の言語では、 printfを使用できます 文字列をフォーマットする関数です。Cを使用したことがある場合は、おそらくそのことに精通しているでしょう。 printfを使用するには フォーマット指定子のリストと変数または値のリストを定義する必要があります。 Ruby文字列フォーマット入門 sprintf はRubyでも利用できます。この投稿では、よ

  2. Javaで文字列を比較する方法

    文字列が等しいかどうかを比較するには、Stringオブジェクトのequalsを使用する必要があります またはequalsIgnoreCase メソッド。 ==を使用すべきでない理由もわかります 文字列を比較する演算子。 文字列とequals()メソッドの比較 Javaで2つの文字列を比較する必要があり、文字列の大文字と小文字も気にする必要がある場合は、equals()を使用できます。 メソッド。 たとえば、次のスニペットは、文字列の2つのインスタンスが大文字小文字を含むすべての文字で等しいかどうかを判断します。 public class CompareTwoStrings { p