整数の配列があります。
例えば:
array = [123,321,12389]
それらの合計を取得するための良い方法はありますか?
そんなこと知ってる
sum = 0
array.each { |a| sum+=a }
動作します。
これを試して:
array.inject(0){|sum,x| sum + x }
(注:0
ベースケースは0
、ではなく空の配列で返されるようにするために必要ですnil
)
array.reduce(0, :+)
と同等ですがarray.inject(0, :+)
、Reduceという用語は、 MapReduceプログラミングモデルの台頭とともに、より一般的な言葉になりつつあります。
インジェクト、リデュース、フォールド、アキュムレート、および圧縮はすべて、フォールディング関数のクラスと同義です。コードベース全体の一貫性が最も重要だと思いますが、さまざまなコミュニティが1つの単語を別の単語よりも好む傾向があるため、それでも代替案を知っておくと便利です。
map-reduceの言い回しを強調するために、これは、その配列に何が含まれるかについてもう少し寛容なバージョンです。
array.map(&:to_i).reduce(0, :+)
いくつかの追加の関連読書:
または(比較のために)、Railsがインストールされている場合(実際にはActiveSupportのみ):
require 'activesupport'
array.sum
Ruby> = 2.4.0の場合sum
、Enumerablesから使用できます。
[1, 2, 3, 4].sum
基本クラスをmokeypatchするのは危険です。危険が好きで、古いバージョンのRubyを使用している場合は#sum
、Array
クラスに追加できます。
class Array
def sum
inject(0) { |sum, x| sum + x }
end
end
適切な名前のメソッドを使用できますEnumerable#sum
。これには多くの利点inject(:+)
がありますが、最後に読むべき重要な注意事項もいくつかあります。
(1..100).sum
#=> 5050
[1, 2, 4, 9, 2, 3].sum
#=> 21
[1.9, 6.3, 20.3, 49.2].sum
#=> 77.7
このメソッドは。と同等ではありません#inject(:+)
。例えば
%w(a b c).inject(:+)
#=> "abc"
%w(a b c).sum
#=> TypeError: String can't be coerced into Integer
また、
(1..1000000000).sum
#=> 500000000500000000 (execution time: less than 1s)
(1..1000000000).inject(:+)
#=> 500000000500000000 (execution time: upwards of a minute)
なぜこのようなのかについての詳細は、この回答を参照してくださいsum
。
Ruby 2.4+/Rails-array.sum
つまり[1, 2, 3].sum # => 6
Rubypre2.4-array.inject(:+)
またはarray.reduce(:+)
*注:この#sum
メソッドは2.4に新しく追加されたため、Railsだけでなく純粋なルビーでもenumerable
使用できるようになります。array.sum
多様性のために、配列が数値の配列ではなく、数値(例:金額)であるプロパティを持つオブジェクトの配列である場合にも、これを行うことができます。
array.inject(0){|sum,x| sum + x.amount}
ルビー1.8.7の方法は次のとおりです。
array.inject(0, &:+)
Ruby 2.4.0がリリースされ、Enumerable#sumメソッドがあります。だからあなたはすることができます
array.sum
ドキュメントからの例:
{ 1 => 10, 2 => 20 }.sum {|k, v| k * v } #=> 50
(1..10).sum #=> 55
(1..10).sum {|v| v * 2 } #=> 110
nil値の配列の場合、コンパクトにしてから合計を注入できます。
a = [1,2,3,4,5,12,23.45,nil,23,nil]
puts a.compact.inject(:+)
また、以下を可能にし[1,2].sum{|x| x * 2 } == 6
ます:
# http://madeofcode.com/posts/74-ruby-core-extension-array-sum
class Array
def sum(method = nil, &block)
if block_given?
raise ArgumentError, "You cannot pass a block and a method!" if method
inject(0) { |sum, i| sum + yield(i) }
elsif method
inject(0) { |sum, i| sum + i.send(method) }
else
inject(0) { |sum, i| sum + i }
end
end
end
ゴルフのように感じるなら、あなたはすることができます
eval [123,321,12389]*?+
これにより、文字列 "123 + 321 + 12389"が作成され、関数evalを使用して合計が計算されます。これはゴルフ目的のみであり、適切なコードで使用しないでください。
方法1:
[1] pry(main)> [1,2,3,4].sum
=> 10
[2] pry(main)> [].sum
=> 0
[3] pry(main)> [1,2,3,5,nil].sum
TypeError: nil can't be coerced into Integer
方法2:
[24] pry(main)> [].inject(:+)
=> nil
[25] pry(main)> [].inject(0, :+)
=> 0
[4] pry(main)> [1,2,3,4,5].inject(0, :+)
=> 15
[5] pry(main)> [1,2,3,4,nil].inject(0, :+)
TypeError: nil can't be coerced into Integer
from (pry):5:in `+'
方法3:
[6] pry(main)> [1,2,3].reduce(:+)
=> 6
[9] pry(main)> [].reduce(:+)
=> nil
[7] pry(main)> [1,2,nil].reduce(:+)
TypeError: nil can't be coerced into Integer
from (pry):7:in `+'
方法4: 配列にnilと空の値が含まれている場合、デフォルトで上記の関数を使用すると、reduce、sum、injectすべてが
TypeError:nilを整数に強制変換することはできません
あなたはこれを克服することができます、
[16] pry(main)> sum = 0
=> 0
[17] pry(main)> [1,2,3,4,nil, ''].each{|a| sum+= a.to_i }
=> [1, 2, 3, 4, nil, ""]
[18] pry(main)> sum
=> 10
方法6: 評価
文字列内のRuby式を評価します。
[26] pry(main)> a = [1,3,4,5]
=> [1, 3, 4, 5]
[27] pry(main)> eval a.join '+'
=> 13
[30] pry(main)> a = [1,3,4,5, nil]
=> [1, 3, 4, 5, nil]
[31] pry(main)> eval a.join '+'
SyntaxError: (eval):1: syntax error, unexpected end-of-input
1+3+4+5+
簡単な方法でもできます
def sum(numbers)
return 0 if numbers.length < 1
result = 0
numbers.each { |num| result += num }
result
end
次のように.mapと.sumを使用できます。
array.map { |e| e }.sum