brainfck
brainfck

Reputation: 9376

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.

Upvotes: 627

Views: 563250

Answers (16)

zenazn
zenazn

Reputation: 14355

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)

Upvotes: 648

jomey
jomey

Reputation: 8739

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

Upvotes: 863

Ulysse BN
Ulysse BN

Reputation: 11423

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.

Upvotes: 1

jrhicks
jrhicks

Reputation: 14997

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

Upvotes: 97

pwnchaurasia
pwnchaurasia

Reputation: 1499

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(:+)

Upvotes: 4

raj_acharya
raj_acharya

Reputation: 665

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+

Upvotes: 2

typo
typo

Reputation: 1071

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.

Upvotes: 22

Eli Sadoff
Eli Sadoff

Reputation: 7308

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.

Upvotes: 51

Santhosh
Santhosh

Reputation: 29174

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

Upvotes: 6

Evan
Evan

Reputation: 7416

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:

Upvotes: 304

shabdar
shabdar

Reputation: 356

You can use .map and .sum like:

array.map { |e| e }.sum

Upvotes: -10

I am PK
I am PK

Reputation: 6764

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

Upvotes: -1

HashFail
HashFail

Reputation: 536

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}

Upvotes: 19

grosser
grosser

Reputation: 15097

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

Upvotes: 4

Vova
Vova

Reputation: 319

ruby 1.8.7 way is the following:

array.inject(0, &:+) 

Upvotes: 18

Mike Woodhouse
Mike Woodhouse

Reputation: 52326

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

require 'activesupport'
array.sum

Upvotes: 118

Related Questions