web-dev-qa-db-ja.com

RuboCopが.times.mapをArray.newに置き換えることを提案するのはなぜですか?

RuboCopは提案します:

Array.newの代わりにブロックで.times.map.を使用します

警官のための docs では:

この警官は.xmap呼び出しをチェックします。ほとんどの場合、このような呼び出しは明示的な配列の作成に置き換えることができます。

例:

# bad
9.times.map do |i|
  i.to_s
end

# good
Array.new(9) do |i|
  i.to_s
end

置き換えることができることはわかっていますが、9.times.mapは英語の文法に近く、コードが何をするのかを理解しやすいと感じています。

なぜ交換する必要があるのですか?

36
shirakia

後者の方がパフォーマンスが優れています。ここに説明があります: この警官が追加されたプルリクエスト

次のような呼び出しをチェックします。

9.times.map { |i| f(i) }
9.times.collect(&foo)

代わりにこれを使用することをお勧めします:

Array.new(9) { |i| f(i) }
Array.new(9, &foo)

新しいコードはほぼ同じサイズですが、使用するメソッド呼び出しが少なく、メモリ消費が少なく、動作が少し速く、私の意見ではより読みやすくなっています。

私は何度も何度も発生しました。{map、collect}は、Rails、GitLab、Rubocop、およびいくつかのクローズドソースアプリなど、よく知られたさまざまなプロジェクトで使用されています。

ベンチマーク:

Benchmark.ips do |x|
  x.report('times.map') { 5.times.map{} }
  x.report('Array.new') { Array.new(5){} }
  x.compare!
end
__END__
Calculating -------------------------------------
           times.map    21.188k i/100ms
           Array.new    30.449k i/100ms
-------------------------------------------------
           times.map    311.613k (± 3.5%) i/s -      1.568M
           Array.new    590.374k (± 1.2%) i/s -      2.954M

Comparison:
           Array.new:   590373.6 i/s
           times.map:   311612.8 i/s - 1.89x slower

Lintが警官のための正しい名前空間であるかどうか、今はわかりません。パフォーマンスに移動する必要があるかどうかをお知らせください。

また、既存のコードが壊れる可能性があるため、自動修正は実装していません。誰かが何か特別なことをするためにFixnum#timesメソッドを再定義した場合。自動修正を適用すると、コードが破損します。

35
MikDiet

読みやすいと感じた場合は、それに合わせてください。

これはパフォーマンスルールであり、アプリケーションのほとんどのコードパスはおそらくパフォーマンスに影響を与えません。個人的には、時期尚早な最適化よりも読みやすさを優先することに常にオープンです。

それは言った

100.times.map { ... }
  • timesEnumeratorオブジェクトを作成します
  • mapは、最適化できずにそのオブジェクトを列挙します。たとえば、配列のサイズは事前にわからないため、動的により多くのスペースを再割り当てする必要があり、mapはそのように実装されているため、Enumerable#eachを呼び出して値を列挙する必要があります。

一方

Array.new(100) { ... }
  • newはサイズの配列Nを割り当てます
  • そして、ネイティブループを使用して値を入力します
12
akuhn

一定回数呼び出されたブロックの結果をマップする必要がある場合、次のオプションがあります。

Array.new(n) { ... }

そして:

n.times.map { ... }

後者はn = 10では約60%遅く、n > 1_000では約40%に低下します。

注:対数目盛!

enter image description here

5
Drenmi