How to sum array of numbers in Ruby?

503,381

Solution 1

Try this:

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

See Ruby's Enumerable Documentation

(note: the 0 base case is needed so that 0 will be returned on an empty array instead of nil)

Solution 2

For ruby >= 2.4 you can use sum:

array.sum

For ruby < 2.4 you can use inject:

array.inject(0, :+)

Note: the 0 base case is needed otherwise nil will be returned on empty arrays:

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

Solution 3

array.reduce(0, :+)

While equivalent to array.inject(0, :+), the term reduce is entering a more common vernacular with the rise of MapReduce programming models.

inject, reduce, fold, accumulate, and compress are all synonymous as a class of folding functions. I find consistency across your code base most important, but since various communities tend to prefer one word over another, it’s nonetheless useful to know the alternatives.

To emphasize the map-reduce verbiage, here’s a version that is a little bit more forgiving on what ends up in that array.

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

Some additional relevant reading:

Solution 4

Alternatively (just for comparison), if you have Rails installed (actually just ActiveSupport):

require 'activesupport'
array.sum

Solution 5

For Ruby >=2.4.0 you can use sum from Enumerables.

[1, 2, 3, 4].sum

It is dangerous to mokeypatch base classes. If you like danger and using an older version of Ruby, you could add #sum to the Array class:

class Array
  def sum
    inject(0) { |sum, x| sum + x }
  end
end
Share:
503,381
brainfck
Author by

brainfck

Updated on July 19, 2022

Comments

  • brainfck
    brainfck almost 2 years

    I have an array of integers.

    For example:

    array = [123,321,12389]
    

    Is there any nice way to get the sum of them?

    I know, that

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

    would work.

  • Peter
    Peter over 14 years
    jorney's array.inject(:+) is more efficient.
  • Pablo Cantero
    Pablo Cantero about 13 years
    How can I use this way to sum a attribute from object. My array [product1, product2] I want to sum product1.price + product2.price. Is it possible using array.inject(:+)?
  • Diego Basch
    Diego Basch almost 13 years
    Pablo: You can do: array.map{|p| p.price}.inject(+:)
  • markquezada
    markquezada over 12 years
    You can use a similar trick with the map method: array.map(&:price).inject(:+)
  • johnf
    johnf over 12 years
    array.map(&:price).inject(0, :+) is a bit safer. It makes sure that if you have an empty list you get 0 instead of nil.
  • dcashman
    dcashman about 12 years
    Newer versions of activesupport don't actually load all extensions by default. You'll want to either require just the sum module: require 'active_support/core_ext/enumerable.rb', or require all of active support: require 'active_support/all'. More about it here: API Docs
  • Kamil Szot
    Kamil Szot over 11 years
    array.inject(:+) seems to cause trouble in Ruby 1.8.6 Exceptions " LocalJumpError : no block given" might pop up.
  • Kamil Szot
    Kamil Szot over 11 years
    In rails array.sum might give you sum of the array values.
  • everett1992
    everett1992 about 11 years
    using array.map(...).inject(...) is inefficient, you will iterate through all data twice. Try array.inject(0) { |sum, product| sum += product.price }
  • everett1992
    everett1992 about 11 years
    I agree, reduce tells me more of what the function does, but inject does sound much cooler.
  • Boris Stitnicky
    Boris Stitnicky about 11 years
    In most cases, I prefer to use reduce, which is an alias of inject (as in array.reduce( :+ )).
  • yurisich
    yurisich almost 11 years
    @Boris Also, Rubycop will warn you for using inject rather than reduce.
  • Jerska
    Jerska over 10 years
    Agree with the last comment, you gave me the best answer.
  • Richard Jones
    Richard Jones about 10 years
    This is equivalent to doing: array.map(&:amount).inject(0, :+). See other answers.
  • HashFail
    HashFail about 10 years
    In a way, yes. However, using map then inject requires you to loop through the array twice: once to create a new array, the other to sum the members. This method is slightly more verbose, but also more efficient.
  • oligan
    oligan almost 10 years
    If you read my 2011 comment, and it's still relevant as you're using 1.8.6, please upgrade!
  • Cameron Martin
    Cameron Martin over 9 years
    @everett1992 In most cases, this is probably a premature optimisation.
  • Cameron Martin
    Cameron Martin over 9 years
    @everett1992 and as it turns out, not even an optimisation at all. Doing it in two stages is consistently faster for me. gist.github.com/cameron-martin/b907ec43a9d8b9303bdc
  • acjay
    acjay about 9 years
    The one comment I would make is that reduce and map as higher-order functions predate MapReduce. The inspiration runs the other way. And in the MapReduce sense, it's a somewhat different operation than a simple functional reduce, having implications for how different machines communicate.
  • Arnold Roa
    Arnold Roa over 8 years
    What is the point of do a map returning same element? this is exactly the same than array.sum
  • user229044
    user229044 over 8 years
    Never mind that activesupport is a massive dependency to drag into a project to go from array.inject(:+) to array.sum.
  • Per Lundberg
    Per Lundberg almost 8 years
    Nitpick to an otherwise good comment: it should be require 'active_support/core_ext/enumerable' without the .rb suffix, since that's added implicitly.
  • Fernando Pelliccioni
    Fernando Pelliccioni almost 8 years
    Ken Iverson introduced the operator / called "reduction operator" in the programming language APL. Source: Iverson, Kenneth. 1962. A Programming Language. Wiley. Another source: "Notation as a Tool of Thought", 1979 ACM Turing Award Lecture, Kenneth E. Iverson, dl.acm.org/ft_gateway.cfm?id=1283935&type=pdf
  • user3467349
    user3467349 almost 8 years
    Please don't do this
  • YoTengoUnLCD
    YoTengoUnLCD over 7 years
    @user3467349 why?
  • user3467349
    user3467349 over 7 years
    Monkeypatching base classes is not nice.
  • Ulysse BN
    Ulysse BN over 7 years
    Moreover array.sum doesn’t exist in ruby. See Mike Woodhouse answer
  • amoebe
    amoebe over 7 years
    Ruby 2.4.0 was released today with this feature included! 🎉
  • typo
    typo over 7 years
    @amoebe you are correct! Glad to see this useful feature included.
  • installero
    installero about 7 years
    It does now in Ruby 2.4.0
  • Peter H. Boling
    Peter H. Boling about 7 years
    The point he is making is that you don't need to do the Monkey Patch for Ruby >= 2.4, and that monkey patching is dangerous, and that you can now sum enumerables natively, but there is also a way to backport the functionality.
  • Eldritch Conundrum
    Eldritch Conundrum over 6 years
    Downvoted because your implementation returns nil on empty arrays.
  • Cary Swoveland
    Cary Swoveland about 6 years
    As noted, Enumerable#sum (and Array#sum) were introduced in Ruby v2.4. Importantly, they do not have the same behavior as your Array#sum; namely, they take an optional argument and an optional block. Defining Array#sum as you have would result in an exception being raised wherever sum appeared in the code with an argument or block.
  • Eldritch Conundrum
    Eldritch Conundrum about 6 years
    @caryswoveland How many languages do you know in which sum([]) is not zero? Anyway, someone already fixed it since my last comment.
  • Cary Swoveland
    Cary Swoveland about 6 years
    @EldritchConundrum, zero. I deleted my comment, which was poorly thought out.
  • rmcsharry
    rmcsharry almost 5 years
    Apparently it is not more efficient, see gist.github.com/cameron-martin/b907ec43a9d8b9303bdc - credit to the comments in this answer: stackoverflow.com/a/1538949/1028679
  • user229044
    user229044 almost 4 years
    This is very non-idiomatic Ruby, it looks like Ruby written by a C programmer. In Ruby, inject or sum are preferred.
  • Joshua Pinter
    Joshua Pinter about 3 years
    If you need to supply a default value for when the Array is empty, like if you want to return a Money object instead of an Integer, you can do something like array.sum( 0.to_money( "USD" ) ).
  • Joshua Pinter
    Joshua Pinter about 3 years
    If you need to supply a default value for when the Array is empty, like if you want to return a Money object instead of an Integer, you can do something like array.sum( 0.to_money( "USD" ) ).