web-dev-qa-db-ja.com

Rubyで配列内のオブジェクトのプロパティを合計する方法

Rubyの配列要素を合計するために、injectメソッドを使用できることを理解しています。

array = [1,2,3,4,5];
puts array.inject(0, &:+) 

しかし、オブジェクト配列内のオブジェクトのプロパティを合計するにはどうすればよいですか?

オブジェクトの配列があり、各オブジェクトには、たとえば、プロパティ「キャッシュ」があります。したがって、私は彼らの現金残高を合計して1つの合計にしたいと思います。何かのようなもの...

array.cash.inject(0, &:+) # (but this doesn't work)

おそらく財産キャッシュのみで構成される新しい配列を作成し、これを合計することができると思いますが、可能であれば、よりクリーンな方法を探しています!

46
Spike Fitsch
array.map(&:cash).inject(0, &:+)

または

array.inject(0){|sum,e| sum + e.cash }
61
Yuri Barbashov

In Ruby on Railsまた試してみてください:

array.sum(&:cash)

注入ビジネスのショートカットであり、私にとっては読みやすいようです。
http://api.rubyonrails.org/classes/Enumerable.html

49
jacklin

#reduceはブロックを取ります(&:+は、+)。これはあなたがしたいことをする一つの方法です:

array.reduce(0) { |sum, obj| sum + obj.cash }
10
Theo

最も簡潔な方法:

array.map(&:cash).sum

マップの結果の配列にnilアイテムがある場合:

array.map(&:cash).compact.sum
3
vicocas

初期注入を使用する必要はなく、プラス操作を短くすることができます

array.map(&:cash).inject(:+)
1
megas

ここでいくつかの興味深いベンチマーク

array = Array.new(1000) { OpenStruct.new(property: Rand(1000)) }

Benchmark.ips do |x|
  x.report('map.sum') { array.map(&:property).sum }
  x.report('inject(0)') { array.inject(0) { |sum, x| sum + x.property } }
  x.compare!
end

そして結果

Calculating -------------------------------------
             map.sum   249.000  i/100ms
           inject(0)   268.000  i/100ms
-------------------------------------------------
             map.sum      2.947k (± 5.1%) i/s -     14.691k
           inject(0)      3.089k (± 5.4%) i/s -     15.544k

Comparison:
           inject(0):     3088.9 i/s
             map.sum:     2947.5 i/s - 1.05x slower

ご覧のとおり、注入が少し速くなります

1
mpospelov

合計の開始値が0の場合、合計のみが注入と同じです。

array.map(&:cash).sum

そして、私はブロック版を好むでしょう:

array.sum { |a| a.cash }

多くの場合、Proc fromシンボルは制限が多すぎるためです(パラメーターがないなど)。

(Active_Supportが必要)

1