Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby range.reduce with hash accumulator

Tags:

range

ruby

hash

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 }
like image 888
Cruz Nunez Avatar asked Jan 05 '23 01:01

Cruz Nunez


1 Answers

You could use each_with_object instead of reduce:

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

enumerable.each_with_object(obj) { ... } returns obj so you don't need the artificial-feeling ; h in the block that you'd need with reduce.

Note that the order of the arguments to the block is different than with reduce.

like image 70
mu is too short Avatar answered Jan 14 '23 06:01

mu is too short