Cruz Nunez Cruz Nunez - 26 days ago 9
Ruby Question

Ruby range.reduce with hash accumulator

I have this method



def heights
(60..68).reduce({}) { |h, i| h.merge!( { %(#{i/12}'#{i%12}") => i } ) }
end


it returns a hash of heights

{
"5'0\"" => 60, "5'1\"" => 61, "5'2\"" => 62,
"5'3\"" => 63, "5'4\"" => 64, "5'5\"" => 65,
"5'6\"" => 66, "5'7\"" => 67, "5'8\"" => 68
}


That's what I want. However, I don't like using the
merge!
method. I'd much rather use the
hash[key] = value
syntax for assignment:

def heights
(60..68).reduce({}) { |h, i| h[%(#{i/12}'#{i%12}")] = i }
end


But this code throws errors. I know that with reduce, in your pipes you can name your accumulator and element.

I also understand that

sum = 0
(1..5).each { |i| sum += i }


is equivalent to

(1..5).reduce(0) { |sum, i| sum + i }


So why doesn't this

hash = {}
(1..5).each { |i| hash[i.to_s] = i }


work the same as

(1..5).reduce({}) { |hash, i| hash["#{i}"] = i }

Answer

Block in reduce should return new accumulator. In your case

(1..5).reduce({}) { |hash, i| hash["#{i}"] = i }

block returns i, which is an integer, so on the second iteration you will try to call [] on an integer. What you need it this:

(1..5).reduce({}) { |hash, i| hash["#{i}"] = i; hash }