the following code return this error:
block in find_word_lengths': undefined method `[]=' for 3:Integer (NoMethodError)
animals = ['cat', 'horse', 'rabbit', 'deer']
def find_word_lengths(word_list)
word_list.reduce(Hash.new()) do |result, animal|
result[animal] = animal.length
end
end
puts find_word_lengths(animals)
The return value of the block is the accumulator value for the next iteration. That is how a fold works.
Assignments in Ruby evaluate to the right-hand side. So, in the first iteration of reduce, the block evaluates to 3 (the length of 'cat'). Which means that in the second iteration of reduce, result is 3, and you are essentially running
3['horse'] = 5
# which is equivalent to
3.[]=('horse', 5)
Which is why you are getting the error message that the Integer 3 does not respond to the message []=.
So, you need to make sure that your block always returns the value that you want to use for the accumulator in the next iteration. Something like this:
word_list.reduce(Hash.new()) do |result, animal|
result.tap {|result| result[animal] = animal.length }
end
This would be the obvious solution, although somewhat cheating.
word_list.reduce(Hash.new()) do |result, animal|
result.merge(animal => animal.length)
end
Would be more idiomatic.
However, when you want to fold into a mutable object, it makes more sense to use Enumerable#each_with_object instead of Enumerable#reduce. each_with_object ignores the result of the block, and simply passes the same object every time. Note that somewhat confusingly, the order of the block parameters is swapped in each_with_object compared to reduce.
word_list.each_with_object(Hash.new()) do |animal, result|
result[animal] = animal.length
end
But I guess the most idiomatic solution would be something like this:
word_list.map {|word| [word, word.length] }.to_h
By the way, in Ruby, it is idiomatic to leave out the parentheses for the argument list if you are not passing any arguments, so Hash.new() should be Hash.new instead. Even more important than being idiomatic is to be consistent – confusingly, you leave out the parentheses for animal.length, but not for Hash.new
Even more idiomatically, you would use the Hash literal notation instead of the Hash::new method, i.e. you should use {} instead of Hash.new.