Rubyで数値の配列を合計する方法は?


563

整数の配列があります。

例えば:

array = [123,321,12389]

それらの合計を取得する良い方法はありますか?

そんなこと知ってる

sum = 0
array.each { |a| sum+=a }

うまくいくでしょう。


19
ルビー2.4+が持っていることをしてください。注array.sum
仲の良い友達

Ruby 2.6にはありません。Rubyの贈り物、Rubyの持ち去りのようです。
ロリ

1
@ロリうーん?リンク
steenslag

ごめんなさい。そのとき、自分のrbenvが誤っているため、誤って2.6を使用していると思いました。
ロリ

回答:


612

これを試して:

array.inject(0){|sum,x| sum + x }

Rubyの列挙可能なドキュメントを見る

(注:の代わりに空の配列で返される0ように、基本ケースが必要0ですnil


317
jorneyのarray.inject(:+)方が効率的です。
Peter

3
array.inject(:+)Ruby 1.8.6で問題が発生するようです。例外「LocalJumpError:ブロックが指定されていません」がポップアップする場合があります。
Kamil Szot

34
レールarray.sumでは、配列の値の合計が得られる場合があります。
Kamil Szot

32
ほとんどの場合、(のように)のreduceエイリアスであるを使用することを好みます。injectarray.reduce( :+ )
Boris Stitnicky 2013

3
@Borisまた、Rubycopはinjectではなくを使用するよう警告しますreduce
Droogans 2013

810

またはRuby 1.9の方法を試してください:

array.inject(0, :+)

注:0基本ケースが必要です。それ以外の場合はnil空の配列で返されます。

> [].inject(:+)
nil
> [].inject(0, :+)
0

6
この方法を使用してオブジェクトから属性を合計するにはどうすればよいですか。私の配列[product1、product2] product1.price + product2.priceを合計したい。array.inject(:+)を使用することは可能ですか?
Pablo Cantero 2011

7
同様のトリックをmapメソッドで使用できます:array.map(&:price).inject(:+)
markquezada

100
array.map(&:price).inject(0, :+)少し安全です。空のリストがある場合は、nilの代わりに0を取得します。
johnf 2011年

11
array.map(...)。inject(...)の使用は非効率的です。すべてのデータを2回繰り返します。試してみる array.inject(0) { |sum, product| sum += product.price }
everett1992

4
@ everett1992そして、結局のところ、最適化すらされていません。2つの段階で実行する方が一貫して高速です。gist.github.com/cameron-martin/b907ec43a9d8b9303bdc
Cameron Martin、

290
array.reduce(0, :+)

と同じですがarray.inject(0, :+)reduceという用語は、MapReduceプログラミングモデルの登場により、より一般的な用語になりつつあります

injectreducefoldaccumulatecompressはすべて、折りたたみ関数のクラスと同じ意味です。私はコードベース全体の一貫性が最も重要であると考えていますが、さまざまなコミュニティが1つの単語を別の単語よりも好む傾向があるため、代替案を知ることは役に立ちます。

map-reduceの言い回しを強調するために、その配列で最終的に何が発生するかを少し許容するバージョンを次に示します。

array.map(&:to_i).reduce(0, :+)

追加の関連する読み物:


11
私は同意しreduceます、関数が何をするかについてもっと教えてくれますが、injectはるかにクールに聞こえます。
everett1992、2013

1
最後のコメントに同意して、あなたは私に最良の答えを与えました。
Jerska 2013

1
私はなるだろう1件のコメントということであるreducemap高階関数は、MapReduceのをさかのぼるよう。インスピレーションは逆に実行されます。MapReduceの意味では、これは単純な機能的な削減とはやや異なる操作であり、さまざまなマシンの通信方法に影響を与えます。
acjay 2015

ケン・アイバーソンは、プログラミング言語APLで演算子/縮約演算子と呼ばれるものを導入しました。出典:アイバーソン、ケネス。1962。プログラミング言語。ワイリー。別の情報源:「思考の道具としての記法」、1979 ACMチューリング賞講演、ケネスE.アイバーソン、dl.acm.org / ft_gateway.cfm?id
Fernando Pelliccioni

112

別の方法として(比較のため)、Railsがインストールされている場合(実際にはActiveSupportのみ):

require 'activesupport'
array.sum

12
activesupportの新しいバージョンでは、デフォルトですべての拡張機能が実際にロードされるわけではありません。sumモジュールのみを必要とするかrequire 'active_support/core_ext/enumerable.rb'、アクティブなサポートをすべて必要とする必要がありますrequire 'active_support/all'。詳細はこちら:API Docs
dcashman 2012年

2
プロジェクトにドラッグしてからに移動するための大きな依存関係activesupportであることを気にしないでください。array.inject(:+)array.sum
貧弱

1
それ以外の場合は適切なコメントへのニッピック:サフィックスは暗黙的に追加されるためrequire 'active_support/core_ext/enumerable'.rbサフィックスを付けないでください。
Lundberg氏による2016

72

Ruby> = 2.4.0の場合sum、Enumerablesから使用できます。

[1, 2, 3, 4].sum

基本クラスをmokeypatchするのは危険です。危険が気になり、古いバージョンのRubyを使用する場合は#sumArrayクラスに追加できます。

class Array
  def sum
    inject(0) { |sum, x| sum + x }
  end
end

1
これを行わないでください
user3467349

@ user3467349なぜですか?
YoTengoUnLCD 2016

15
基本クラスのモンキーパッチは適切ではありません。
user3467349 2016年

1
彼が指摘しているのは、Ruby> = 2.4のモンキーパッチを実行する必要がないこと、そしてモンキーパッチは危険であり、列挙可能オブジェクトをネイティブに合計できるようになりましたが、機能をバックポートする方法もあるということです。
Peter H.Boling 2017

実装が空の配列でnilを返すため、反対投票されました。
Eldritch Conundrum 2017年

45

Ruby 2.4.0の新機能

適切な名前のメソッドを使用できます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ような理由の詳細については、この回答を参照してください。


20

Ruby 2.4以降/ Rails- array.sumie[1, 2, 3].sum # => 6

Ruby pre 2.4- array.inject(:+)またはarray.reduce(:+)

*注意:この#sumメソッドは2.4の新しい追加であり、Railsだけでなく純粋なRubyでもenumerable使用できるようになりますarray.sum


2
Ruby 2.4.0が本日リリースされ、この機能が含まれています!🎉
amoebe

@amoebe正解です!この便利な機能が含まれていることをうれしく思います。
収集

19

多様性のために、配列が数値の配列ではなく、数値(たとえば、金額)のプロパティを持つオブジェクトの配列である場合にも、これを行うことができます。

array.inject(0){|sum,x| sum + x.amount}

3
これは次を実行することと同じですarray.map(&:amount).inject(0, :+)。他の回答を参照してください。
リチャードジョーンズ、

4
ある意味で、はい。ただし、mapthen を使用injectすると、配列を2回ループする必要があります。1つは新しい配列を作成するため、もう1つはメンバーを合計するためです。この方法は少し冗長ですが、より効率的です。
HashFail 14

どうやら効率的ではないようです。gist.github.com/ cameron - martin / b907ec43a9d8b9303bdc-この回答のコメントへのクレジット:stackoverflow.com/a/1538949/1028679
rmcsharry

18

ruby 1.8.7の方法は次のとおりです。

array.inject(0, &:+) 

私の2011年のコメントを読んでも、1.8.6を使用しているためそれがまだ関連している場合は、アップグレードしてください!
Andrew Grimm 2014年

16

あなたは単に使うことができます:

    example = [1,2,3]
    example.inject(:+)

なぜ、この作品:inject(:+)しかし、これはそうではありませんかinject :+
Arnold Roa

@ArnoldRoa "inject:+"私にとってはその作品、どのような結果が得られましたか?
ガネーシャサガレ


5

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

3

また、次のことが可能です[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

3

値がnilの配列の場合、コンパクトにしてから合計を注入できます。

a = [1,2,3,4,5,12,23.45,nil,23,nil]
puts a.compact.inject(:+)


1

ゴルフ気分ならできる

eval([123,321,12389]*?+)

これは文字列「123 + 321 + 12389」を作成し、関数evalを使用して合計を行います。これはゴルフのみを目的としています。適切なコードでは使用しないでください。


1

方法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: Arrayにnilと空の値が含まれている場合、デフォルトで上記の関数を使用すると、reduce、sum、injectすべてが

TypeError:nilはIntegerに強制変換できません

これを克服できます

   [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+

1

配列の合計を行う3つの方法

1) array.inject(0){|sum,x| sum + x }

2) array.inject('+')

3) array.join('+')


0

または、この方法を試すことができます。

def sum arr
  0 if arr.empty
  arr.inject :+
end


0
number = [1..100]

number. each do |n|

    final_number = n.sum

    puts "The sum is #{final_number}"
end

*これは私が新しい開発者としてうまく機能した。[]内の値を変更することで、番号範囲を調整できます



弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.