I'm currently learning ruby and I wrote this piece of code :
def multi_gen
s = []
for i in (3..10)
if i%3 == 0 || i%5 == 0
s<<i
end
end
return s
end
puts multi_gen
def rec_sum(num_arr)
if num_arr == []
return 0
else
num_arr.first + rec_sum(num_arr.shift)
end
end
puts rec_sum(multi_gen)
That should return the sum of all 3 and 5 multiples up to 1000.
But I get an error :
myrbfile.rb:17:in `rec_sum': undefined method `first' for 3:Fixnum (NoMethodError)
from villani.rb:17:in `rec_sum'
from villani.rb:21:in `<main>'
But when I re-write it like this :
def multi_gen
s = []
for i in (3..10)
if i%3 == 0 || i%5 == 0
s<<i
end
end
return s
end
puts multi_gen
def rec_sum(num_arr)
if num_arr == []
return 0
else
num_arr[0] + rec_sum(num_arr[1..num_arr.last])
end
end
puts rec_sum(multi_gen)
I don't get the error.
So why is my first rec_sum functions interpretting my Array as a Fixnum in the first case?
mudasobwa already explained why using
shiftdoesn't give the expected result. Apart from that, your code is somehow unidiomatic.In
multi_genyou are creating an empty array and append elements to it using aforloop. You rarely have to populate an array manually. Instead, you can usually use one of Ruby'sArrayorEnumerablemethods to generate the array.selectis a very common one – it returns an array containing the elements for which the given block returnstrue:In
rec_sum, you checkif num_arr == []. Although this works, you are creating an empty throw-away array. To determine whether an array is empty, you should call itsempty?:To get the remaining elements from the array, you use:
which can be abbreviated by passing a negative index to
[]:There's also
dropwhich might look a little nicer:Another option to get first and remaining elements from an array is Ruby's array decomposition feature (note the
*):You could also consider using a guard clause to return from the method early:
Writing recursive methods is great for learning purposed, but Ruby also has a built-in
summethod:or – since you are using an older Ruby version –
inject: