How to sum array of numbers in Ruby?
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:
- http://ruby-doc.org/core-1.9.3/Enumerable.html#method-i-inject
- http://en.wikipedia.org/wiki/MapReduce
- http://en.wikipedia.org/wiki/Fold_(higher-order_function)
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
brainfck
Updated on July 19, 2022Comments
-
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 over 14 yearsjorney's
array.inject(:+)
is more efficient. -
Pablo Cantero about 13 yearsHow 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 almost 13 yearsPablo: You can do: array.map{|p| p.price}.inject(+:)
-
markquezada over 12 yearsYou can use a similar trick with the map method: array.map(&:price).inject(:+)
-
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 about 12 yearsNewer 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 over 11 years
array.inject(:+)
seems to cause trouble in Ruby 1.8.6 Exceptions " LocalJumpError : no block given" might pop up. -
Kamil Szot over 11 yearsIn rails
array.sum
might give you sum of the array values. -
everett1992 about 11 yearsusing array.map(...).inject(...) is inefficient, you will iterate through all data twice. Try
array.inject(0) { |sum, product| sum += product.price }
-
everett1992 about 11 yearsI agree,
reduce
tells me more of what the function does, butinject
does sound much cooler. -
Boris Stitnicky about 11 yearsIn most cases, I prefer to use
reduce
, which is an alias ofinject
(as inarray.reduce( :+ )
). -
yurisich almost 11 years@Boris Also, Rubycop will warn you for using
inject
rather thanreduce
. -
Jerska over 10 yearsAgree with the last comment, you gave me the best answer.
-
Richard Jones about 10 yearsThis is equivalent to doing:
array.map(&:amount).inject(0, :+)
. See other answers. -
HashFail about 10 yearsIn a way, yes. However, using
map
theninject
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 almost 10 yearsIf you read my 2011 comment, and it's still relevant as you're using 1.8.6, please upgrade!
-
Cameron Martin over 9 years@everett1992 In most cases, this is probably a premature optimisation.
-
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 about 9 yearsThe one comment I would make is that
reduce
andmap
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 over 8 yearsWhat is the point of do a map returning same element? this is exactly the same than
array.sum
-
user229044 over 8 yearsNever mind that
activesupport
is a massive dependency to drag into a project to go fromarray.inject(:+)
toarray.sum
. -
Per Lundberg almost 8 yearsNitpick 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 almost 8 yearsKen 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 almost 8 yearsPlease don't do this
-
YoTengoUnLCD over 7 years@user3467349 why?
-
user3467349 over 7 yearsMonkeypatching base classes is not nice.
-
Ulysse BN over 7 yearsMoreover array.sum doesn’t exist in ruby. See Mike Woodhouse answer
-
amoebe over 7 yearsRuby 2.4.0 was released today with this feature included! 🎉
-
typo over 7 years@amoebe you are correct! Glad to see this useful feature included.
-
installero about 7 yearsIt does now in Ruby 2.4.0
-
Peter H. Boling about 7 yearsThe 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 over 6 yearsDownvoted because your implementation returns nil on empty arrays.
-
Cary Swoveland about 6 yearsAs 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. DefiningArray#sum
as you have would result in an exception being raised whereversum
appeared in the code with an argument or block. -
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 about 6 years@EldritchConundrum, zero. I deleted my comment, which was poorly thought out.
-
rmcsharry almost 5 yearsApparently 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 almost 4 yearsThis is very non-idiomatic Ruby, it looks like Ruby written by a C programmer. In Ruby,
inject
orsum
are preferred. -
Joshua Pinter about 3 yearsIf you need to supply a default value for when the
Array
is empty, like if you want to return aMoney
object instead of anInteger
, you can do something likearray.sum( 0.to_money( "USD" ) )
. -
Joshua Pinter about 3 yearsIf you need to supply a default value for when the
Array
is empty, like if you want to return aMoney
object instead of anInteger
, you can do something likearray.sum( 0.to_money( "USD" ) )
.