I have code:
class Scene
def initialize(number)
@number = number
end
attr_reader :number
end
scenes = [Scene.new("one"), Scene.new("one"), Scene.new("two"), Scene.new("one")]
groups = scenes.inject({}) do |new_hash, scene|
new_hash[scene.number] = [] if new_hash[scene.number].nil?
new_hash[scene.number] << scene
end
When I'm lauching it I get error:
freq.rb:11:in `[]': can't convert String into Integer (TypeError)
from freq.rb:11:in `block in <main>'
from freq.rb:10:in `each'
from freq.rb:10:in `inject'
from freq.rb:10:in `<main>'
If I change scenes to:
scenes = [Scene.new(1), Scene.new(1), Scene.new(2), Scene.new(1)]
the problem dissapear.
Why I get error message in the first case? Why Ruby decide to convert scene.number from String to Integer?
And one additional question about the 'inject' method. When Ruby initialize the 'new_hash' variable and how can Ruby know the type of this variable?
try:
groups = scenes.inject({}) do |new_hash, scene| new_hash[scene.number] = [] if new_hash[scene.number].nil? new_hash[scene.number] << scene new_hash end
Ruby takes the empty hash passed into inject() and sets new_hash to that. When the block ends the return value gets used to initialize new_hash the next time through, i.e., new_hash keeps accumulating the result of the block.
In your original code you were not returning the hash but an array (new_hash[scene.number] is an array) and the next loop through Ruby complained because new_hash[scene.number] was trying to do a lookup into the array with a string value, hence the error you got.
Z.E.D.'s right. See Jay Fields' Thoughts: Ruby: inject for a good explanation of inject
by example.
As presented, your block returns an array. So the new_hash
in |new_hash, scene|
ends up being that array. When Ruby tries to find the array index 'one', it throws the error because 'one' is a String, not an Integer.
All you need to do is return new_hash
as Z.E.D. showed, and you'll get something like this:
{
"two" => [
#<Scene:0x101836470 @number="two">
],
"one" => [
#<Scene:0x101836510 @number="one">,
#<Scene:0x1018364c0 @number="one">,
#<Scene:0x101836420 @number="one">
]
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With