[ruby] How to sum array of numbers in Ruby?

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.

This question is related to ruby arrays math sum

The answer is


Also allows for [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

You can use .map and .sum like:

array.map { |e| e }.sum

Ruby 2.4.0 is released, and it has an Enumerable#sum method. So you can do

array.sum

Examples from the docs:

{ 1 => 10, 2 => 20 }.sum {|k, v| k * v }  #=> 50
(1..10).sum                               #=> 55
(1..10).sum {|v| v * 2 }                  #=> 110

New for Ruby 2.4.0

You can use the aptly named method Enumerable#sum. It has a lot of advantages over inject(:+) but there are some important notes to read at the end as well.

Examples

Ranges

(1..100).sum
#=> 5050

Arrays

[1, 2, 4, 9, 2, 3].sum
#=> 21

[1.9, 6.3, 20.3, 49.2].sum
#=> 77.7

Important note

This method is not equivalent to #inject(:+). For example

%w(a b c).inject(:+)
#=> "abc"
%w(a b c).sum
#=> TypeError: String can't be coerced into Integer

Also,

(1..1000000000).sum
#=> 500000000500000000 (execution time: less than 1s)
(1..1000000000).inject(:+)
#=> 500000000500000000 (execution time: upwards of a minute)

See this answer for more information on why sum is like this.


Ruby 2.4+ / Rails - array.sum i.e. [1, 2, 3].sum # => 6

Ruby pre 2.4 - array.inject(:+) or array.reduce(:+)

*Note: The #sum method is a new addition to 2.4 for enumerable so you will now be able to use array.sum in pure ruby, not just Rails.


for array with nil values we can do compact and then inject the sum ex-

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

Just for the sake of diversity, you can also do this if your array is not an array of numbers, but rather an array of objects that have properties that are numbers (e.g. amount):

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

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:


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

ruby 1.8.7 way is the following:

array.inject(0, &:+) 

Or try the Ruby 1.9 way:

array.inject(0, :+)

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

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

Method 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

Method 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 `+'

Method 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 `+'

Method 4: When Array contains an nil and empty values, by default if you use any above functions reduce, sum, inject everything will through the

TypeError: nil can't be coerced into Integer

You can overcome this by,

   [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

Method 6: eval

Evaluates the Ruby expression(s) in string.

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

You can also do it in easy way

def sum(numbers)
  return 0 if numbers.length < 1
  result = 0
  numbers.each { |num| result += num }
  result
end

If you feel golfy, you can do

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

This will create a string "123+321+12389" and then use function eval to do the sum. This is only for golfing purpose, you should not use it in proper code.


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

require 'activesupport'
array.sum

Examples related to ruby

Uninitialized Constant MessagesController Embed ruby within URL : Middleman Blog Titlecase all entries into a form_for text field Ruby - ignore "exit" in code Empty brackets '[]' appearing when using .where find_spec_for_exe': can't find gem bundler (>= 0.a) (Gem::GemNotFoundException) How to update Ruby Version 2.0.0 to the latest version in Mac OSX Yosemite? How to fix "Your Ruby version is 2.3.0, but your Gemfile specified 2.2.5" while server starting Is the server running on host "localhost" (::1) and accepting TCP/IP connections on port 5432? How to update Ruby with Homebrew?

Examples related to arrays

PHP array value passes to next row Use NSInteger as array index How do I show a message in the foreach loop? Objects are not valid as a React child. If you meant to render a collection of children, use an array instead Iterating over arrays in Python 3 Best way to "push" into C# array Sort Array of object by object field in Angular 6 Checking for duplicate strings in JavaScript array what does numpy ndarray shape do? How to round a numpy array?

Examples related to math

How to do perspective fixing? How to pad a string with leading zeros in Python 3 How can I use "e" (Euler's number) and power operation in python 2.7 numpy max vs amax vs maximum Efficiently getting all divisors of a given number Using atan2 to find angle between two vectors How to calculate percentage when old value is ZERO Finding square root without using sqrt function? Exponentiation in Python - should I prefer ** operator instead of math.pow and math.sqrt? How do I get the total number of unique pairs of a set in the database?

Examples related to sum

Iterating over arrays in Python 3 Get total of Pandas column Pandas: sum DataFrame rows for given columns How to find sum of several integers input by user using do/while, While statement or For statement SQL Sum Multiple rows into one Python Pandas counting and summing specific conditions SELECT query with CASE condition and SUM() Using SUMIFS with multiple AND OR conditions How to SUM parts of a column which have same text value in different column in the same row how to count the total number of lines in a text file using python