How to Sum Array of Numbers in Ruby

How to sum array of numbers in Ruby?

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)

Sum array of numbers

The usual way of doing that would be this:

def sum(nums) nums.reduce(&:+) end

which is short for something like this:

def sum(nums)  nums.reduce(0) { |total, num| total + num } end

I see that Neil posted a similar solution while I was typing this, so I'll just note that reduce and inject are two names for the same method - Ruby has several aliases like this so that people used to different other languages can find what they're looking for. He also left of the &, which is optional when using a named method for reduce/inject, but not in other cases.

Explanation follows.

In Ruby you don't normally use explicit loops (for, while, etc.). Instead you call methods on the collection you're iterating over, and pass them a block of code to execute on each item. Ruby's syntax places the block after the arguments to the method, between either do...end or {...}, so it looks like traditional imperative flow control, but it works differently.

The basic iteration method is each:

[1,2,3].each do |i| puts i end

That calls the block do |i| puts i end three times, passing it 1, then passing it 2, and finally passing it 3. The |i| is a block parameter, which tells Ruby where to put the value(s) passed into the block each time.

But each just throws away the return value of the block calls (in this case, the three nils returned by puts). If you want to do something with those return values, you have call a different method. For example, map returns an array of the return values:

[1,2,3].map do |i| puts i end
#=> [nil, nil, nil]

That's not very interesting here, but it becomes more useful if the block returns something:

[1,2,3].map do |i| 2*i end  
#=> [2,4,6]

If you want to combine the results into a single aggregate return value instead of getting back an array that's the same size as the input, that's when you reach for reduce. In addition to a block, it takes an extra argument, and the block itself is also called with an extra argument. This extra argument is called the "accumulator". The first time the block is called, it gets the argument originally passed to reduce, but from then on, it gets the return value of the previous call to the block, which is how each block call can pass information along to the next.

That makes reduce more general than map; in fact, you can build map out of reduce by passing in an empty array and having the block add to it:

[1,2,3].reduce([]) do |a,i| a + [2*i] end 
#=> [2,4,6]

But since map is already defined, you would normally just use it for that, and only use reduce to do things that are more, well, reductive:

[1,2,3].reduce(0) do |s, i| s + 2*i end  
#=> 12

...which is what we're doing in solving your problem.

Neil and I took a couple extra shortcuts. First, if a block does nothing but call a single method on its parameters and return the result, you can get an equivalent block by prefixing &: to the method name. That is, this:

some_array.reduce(x) do |a,b| a.some_method(b) end

can be rewritten more simply as this:

some_array.reduce(x, &:some_method)

and since a + b in Ruby is really just a more-familiar way of writing the method call a.+(b), that means that you can add up numbers by just passing in &:+:

[1,2,3].reduce(0, &:+)
#=> 6

Next, the initial accumulator value for reduce is optional; if you leave it out, then the first time the block is called, it gets the first two elements of the array. So you can leave off the 0:

[1,2,3].reduce(&:+)
#=> 6

Finally, you normally need the & any time you are passing in a block that is not a literal chunk of code; you can turn blocks into Proc objects and store them in variables that you can pass around to different iterator methods. When passing a variable like that, you indicate that it should be interpreted as a block instead of a regular parameter by putting & in front of it.

Some methods, including reduce, will also accept a bare Symbol (like :+) and create the Proc/block for you, and Neil took advantage of that fact. But other iterator methods, such as map, don't work that way:

irb(main):001:0> [-1,2,-3].map(:abs)
ArgumentError: wrong number of arguments (1 for 0)
from (irb):1:in `map'
from (irb):1
from /usr/bin/irb:12:in `<main>'

So I just always use the &.

irb(main):002:0> [-1,2,-3].map(&:abs)
#=> [1, 2, 3]

There are lots of good online tutorials for Ruby. For more general information about map/reduce and related concepts, and how to apply them to problem-solving, you should search for introductions to "functional programming", which is called that because it treats "functions" (that is, blocks of executable code, which in Ruby are realized as Proc objects) as values just like numbers and strings, which can be passed around, assigned to variables, etc.

How to find array elements that are the sum of a given number

Like @Stefan and @Jorg said in comments there is no easy way to do it. If this was a question to myself, I would probably write down something like this.

arr = [1, 1, 3, 4, 5, 7]
number = 8
result = []

for i in 0..(arr.length) do
arr.combination(i).each do |combination|
result.push(combination) if combination.sum == number
end
end

print result.uniq

How to sum numbers in nested arrays in Ruby?

Not that obvious, but you can pass a class or module to grep to select its instances:

array.grep(Integer)
#=> [20, 3, 3, 20]

or

array.grep(Numeric)
#=> [20, 3, 3, 20]

or to grep_v in order to exclude its instances:

array.grep_v(String)
#=> [20, 3, 3, 20]

This works because grep uses === for pattern matching. If you pass a class, it invokes Module#=== (each class is a module) which returns true if the object is an instance of the receiver:

Integer === 20
#=> true

Integer === 'foo'
#=> false

However, your actual problem can be solved much easier. Given this array:

array = [["R.M", 20], ["R.U-CS", 3], ["R.M-TIC", 3], ["R.J.CONF", 20]]

And assuming that the second value is always a number, you can use sum with a block:

array.sum { |string, number| number }
#=> 46

or to sum each sub-array's last value: (which is the same in this case)

array.sum(&:last)
#=> 46

How to get the sum an array of strings in ruby

You just need to do

array.map(&:to_f).reduce(:+)

Explanation :-

# it give you back all the Float instances from String instances
array.map(&:to_f)
# same as
array.map { |string| string.to_f }
array.map(&:to_f).reduce(:+)
# is a shorthand of
array.map(&:to_f).reduce { |sum, float| sum + float }

Documentation of #reduce and #map.

Summing all numbers in an array

You can utilize the inject method.

[1,2,3].inject(:+) #=> 6

By the looks of your code I'd guess that your incoming array is an array of strings, not an array of numbers. To convert them to decimals (floats) you can use:

sum = add_array.map(&:to_f).inject(:+)
puts sum

This applies the #to_f operation on every element, then passes that to the summing function (#inject(:+))



Related Topics



Leave a reply



Submit