2011-06-21 8 views
3

私はRuby on Rails 3.0.7を使用していますが、idがと等しい要素を除いて、オブジェクト(クラスの要素)の配列を繰り返し処理したいと思います。配列[1]のインデックスに)。パフォーマンス:要素を除く配列を繰り返し処理する

私はeachステートメントにifステートメントを「内部的に」使用することができますし、各「現在の」「考えられる」要素if id == 1を確認することができます。しかし、配列には多くのデータが格納されているので、より良い方法で同じことを達成するために別の方法を見つけたいと思います(毎回ifを実行しないでください)。

どうすればいいですか?

+0

なぜ、配列の先頭に1というIDが設定されていないことを確認してください。 –

+1

なぜ、rubyにarray.except要素メソッドがないのですか? –

答えて

1
a = ['a', 'b', 'c'] 
a.each_with_index.reject {|el,i| i == 1}.each do |el,i| 
    # do whatever with the element 
    puts el 
end 

私見選択を行う代わりに、独自の明示的なif文を使用しての良い方法です。しかし、それはifとほぼ同じパフォーマンスになると思います。

ベンチマーク後に、これにかかる時間が間違いなく遅くなることがわかっていて、それが遅い原因となる選択である場合は、これを簡単に変更して多数の方法:

a = ['a', 'b', 'c'] 
n = 1 
(a.first(n) + a.drop(n + 1)).each do |el| 
    # do whatever with the element 
    puts el 
end 

残念ながら私はこれも単純なifを実行するよりも遅くなると思います。スピードの可能性があると思われるものは、次のとおりです。

a = ['a', 'b', 'c'] 
n = 1 
((0...n).to_a+((n+1)...a.size).to_a).map{|i| a[i]}.each do |el| 
    # do whatever with the element 
    puts el 
end 

しかし、これもやはり速度が遅くなる可能性が高いです。

EDIT

ベンチマークはthis gistです。これらの結果は実際には私を驚かせた、拒絶ははるかに遅い選択肢、続いて範囲。要素を一切削除しなかった後の最高性能は、firstdropを使用して、その周りのすべての要素を選択していました。ベースラインとして何も選択を使用していない割合として

結果:

with if    146% 
with first and drop 104% 
without if   100% 

これは明らかに、これはRubyが実行することができ、おそらく最速の操作でテストしていた、あなたが要素に何をすべきかに大きく依存しています。操作が遅いほど、これらの差異は少なくなります。いつものように:ベンチマークベンチマークベンチマーク

7
  1. makeプログラムの仕事私たちは、小さな 効率を忘れるべきで
  2. プロフィール
  3. 最適化

Donald Knuth said:

、 時間の約97%と言う:時期尚早の最適化をすべてのeのルートは ですvil。今

、あなたのような何か行うことができます:

def f 
    do_something 
end 

f 0 
for i in 2..n 
    f i 
end 

あるいは:

def f 
    yield 0 
    for i in [email protected] 
    yield i 
    end 
end 

f do |i| 
    do_something 
end 

をしかし、あなたはおそらくは、ソートの何かをしたい、との場合はありませんあなたがした、それが重要であることを知った後になるだけです。

最後に、この醜いトリックが実際にあなたのサーバーを実際に少し速く走らせると仮定します。それは価値がありました?

+2

+1、まさに私が言っていることです。 'if id == 1'は一般的に非常に効率的になるでしょう。あなたが実際のパフォーマンスの問題を発見しない限り、それを汗ばませないでください。その後、プロファイラを起動してください。 –

1

ifステートメントは非常に安い操作です。標準のベンチマークツールを使用して確認できます。

require "benchmark" 

array = [1] * 100_000 

Benchmark.bm do |bm| 
    bm.report "with if" do 
    array.each_with_index do |element, i| 
     next if i == 1 
     element - 1 
    end 
    end 

    bm.report "without if" do 
    array.each do |element| 
     element - 1 
    end 
    end 
end 

結果:

   user  system  total  real 
with if  0.020000 0.000000 0.020000 ( 0.018115) 
without if 0.010000 0.000000 0.010000 ( 0.012248) 

それは100個の000素子アレイ上の約0.006秒差です。ボトルネックになり、それが疑われる場合を除いて、気にしないでください。

1

実際のforループのテストには5分かかるかもしれません。それはRubyのサークルでぶつかるかもしれませんが、それが使用する価値がないというわけではありません。各メソッドやマップなどを呼び出すときに、これらのメソッドはループのために何らかの方法で使用します。絶対に避けてください。

また、アレイの大きさにもよるが、あるnでは、もう一方のものよりも速くなる場合もある。この場合、それは絶対に価値がありません。

特定の要素が必要ない場合は、そのデータ行をデータベースに格納する必要はありません。行1と残りの行との違いは何ですか?つまり、なぜそれをスキップしていますか? id = 1の行は常に同じデータを持っていますか?もしそうなら、それを定数として保存するほうが良いでしょうし、あなたの疑問を解決するでしょう。パフォーマンスはほとんどの場合、より多くのメモリを必要とします。 Railsの3は違ったことを行い、そしてあなたがデータを引き出し、ファインダーキーとしてIDを使用していない限り、ID = 1の要素残念ながら0

なり、Knuthの引用は多くのことを誤解取得しに慣れますプログラマが十分に教育されていれば書かれないであろう非効率的で非効率的なコードを考え、5秒間考えた。確かに、あなたが知らないコードを高速化しようと1週間を過ごすことは問題であるか、または軽微な問題であるが、これはKnuthが何を話していたかである。パフォーマンスは、コンピュータサイエンスにおいて最も誤解され濫用されている概念の1つです。

関連する問題