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 nil
s 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
Class ≪≪ Self Idiom in Ruby
Trying to Learn/Understand Ruby Setter and Getter Methods
Pg::Error: Select Distinct, Order by Expressions Must Appear in Select List
How to Avoid Tripping Over Utf-8 Bom When Reading Files
Difference Between Datetime and Time in Ruby
Ruby Objects and Json Serialization (Without Rails)
Failed to Build Gem Native Extension (Installing Compass)
Error: Failed to Build Gem Native Extension on Mavericks
Why Use Ruby'S Attr_Accessor, Attr_Reader and Attr_Writer
Ruby: String Comparison Issues
Confusion With the Assignment Operation Inside a Falsy 'If' Block
How to Get Argument Names Using Reflection
Best Way to Escape and Unescape Strings in Ruby