1

I am creating a method that will take an array of numbers and add them together. I don't want to use inject because I haven't learned it yet. I prefer to start with the basics. I want to use either each or while.

I've been re-writing this code and testing it against rspec, and I keep running into a problem because the first test consists of the array being empty with nil. I tried doing an if else statement to set nil to 0 if the array is empty?, but that didn't seem to work. Here is what I've got right now.

def sum(x)
  total = 0 
  sum.each { |x| total += x}
  total
end

The rspec is testing an empty array [] as well as others that have multiple integers. Thoughts?

Wouter J
  • 41,455
  • 15
  • 107
  • 112

4 Answers4

1

You're not enumerating the array passed in to the method, you're enumerating the variable sum. You want x.each { |x| total += x}, although using x within the {} is a little odd in this case because you've used the name for your method parameter.

Peter Alfvin
  • 28,599
  • 8
  • 68
  • 106
  • Peter!! Many thanks... I thought I had tried the x.each, but I think you are right.. it was strange that I used the x within {} so I decided to change it to num and it not only read clearer, but solved my issue! Thanks for your help! – NicholasJay Aug 22 '13 at 10:58
0

You can use compact! to remove the nils from your array.

def sum(x)
  total = 0
  x.compact! #lose the nils
  x.each { |i| total += i}
  total
end

Edit: If the x being passed to your sum() method is nil, you can check for that with nil?.

The do something like

if x.nil?
  0 #assuming you want to return 0
else
  #rest of your function
0

You want to return nil if the array passed in is empty?

You are getting confused with your identifiers. You are trying to iterate over sum, which is the name of the method, and you are using x as both the method parameter and the iteration block parameter.

I suggest you use something more descriptive, like arr for the method parameter and v for the block parameter (holding the value of each value from the array).

Finally, you need to initialise the total to nil so that the correct value is returned if the array is empty. Unfortunately you can't do arithmetic on nil, so in the code below I have added a line to set total to zero if it isn't already set.

This will do what you ask.

def sum(arr)
  total = nil
  arr.each do |v|
    total = 0 unless total
    total += v
  end
  total
end

p sum [1,2,3]
p sum []

output

6
nil
Borodin
  • 126,100
  • 9
  • 70
  • 144
-1

You could create a new instance method for the Array class:

class Array
  def sum
    total = 0.0
    self.each {|x| total += x if ['Fixnum', 'Float'].include?(x.class.name)}
    total%1==0 ? total.to_i : total
  end
end

Then you would use it like so:

puts [].sum                     # => 0
puts [1, 2, 3].sum              # => 6
puts [2, nil, "text", 4.5].sum  # => 6.5
tigeravatar
  • 26,199
  • 5
  • 30
  • 38