Eric D. <lists / ruby-forum.com> wrote:
> I am trying to create a sum method for an empty array, that will return
> "0" if there is nothing in it and the sum of the values if there are
> values called through it. I have seen other ways on the internet, but I
> am relatively new to this, and am under the impression that this can be
> done with while loops or .each iteration. Below are various things I
> tried, some were actual thoughts some were out of sheer frustration.

I applaud all efforts to learn how things work. That said, there is a
method which does this already: inject/reduce (they are synonyms).

But let's look at what you're doing.

> Thanks for your help!
> 1.
> def sum (array)

The method accepts an array passed in local variable `array`.
> 
> array = []

You destroy any information you've passed in `array` by resetting it here.

> while array >0

This construction makes little sense, as an Array (`array` is an
instance of the Array class) cannot be compared to a Fixnum (which is
what 0 is.)

But then:

> array.each { |a| sum+=a }

You use another loop to run through `array`. This is probably what you
mean entirely and there is no need for an outer while loop.

However, the local variable `sum` is declared implicitly inside the
block {|a| sum+=a}. There are two problems here:

1. `sum` is initially nil, and nil does not accept += (or +)
2. `sum` will not be available outside the block

> end
> 
> 2.
> 
> def sum
> x= []

This time, you aren't overwriting any method input, but you also
hardwire the `x` array to an empty array. Not a very useful method.

> x.each{|element| element +element }

More problems here. You've omitted the egregious while loop, which is
good. But your block is not doing anything in particular. The current
element in `x` is added to itself, but isn't stored anywhere.

Trying this out in irb:

2.0.0p195 :001 > x = (1..10).to_a
 => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
2.0.0p195 :002 > x.each{|e| e+e}
 => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
2.0.0p195 :003 > 

To see what's happening inside the block, let's add `tap`:

2.0.0p195 :003 > x.each{|e| (e+e).tap{|t| puts "tapped e+e: #{t}"} }
tapped e+e: 2
tapped e+e: 4
tapped e+e: 6
tapped e+e: 8
tapped e+e: 10
tapped e+e: 12
tapped e+e: 14
tapped e+e: 16
tapped e+e: 18
tapped e+e: 20
 => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 

Probably not what you wanted.


>   end
> 
> 3.
> def sum(array)
> 
>   while array.length > 0

This may seem like it should work, but you are not actually changing the
length of `array` so it should go on forever.

>     puts "#{array[x+y+z]}"

This is insteresting, but where do you define the variables `x`, `y`,
and `z`? This should have elicited an error message straight away.

>   else
>     puts "0"

There was no `end` in this block.



Let's drop back a second and just look at the algorithm one can use to
find the sum of number in an array. No ruby, just pseudo-code.

Given an array of numeric elements,
When I initialize a sum variable to zero,
And I loop through the array with an index,
And I add the value of the array element at the current index to the sum
variable,
Then I will have the sum of the elements in the array.

Someone's already given the inject/reduce version:

(using x from before)

2.0.0p195 :007 > x.inject(:+)
 => 55 

But let's look at this in a method:

=== sum.rb
def sum(a) # Given an array of numeric elements,
  sum = 0 # When I initialize a sum variable to zero,
  a.each_index do |i| # And I loop through array with an index,
    sum += a[i] # And I add the value of the array element
                # at the current index to the sum
                # variable,
  end
  sum # Then I will have the sum of the elements in the array.
end
===
  
2.0.0p195 :010 > def sum(a) ; sum=0;a.each_index{|i| sum+=a[i]}; sum; end
 => nil 
2.0.0p195 :011 > sum x
 => 55 

There's at least a dozen ways to write this; this is but one. Comparing
the method sum to inject, I much prefer inject.