Stephen Smith
Stephen Smith

Reputation: 387

Set multiple keys to the same value at once for a Ruby hash

I'm trying to create this huge hash, where there are many keys but only a few values.

So far I have it like so...

du_factor = {
  "A" => 1,
  "B" => 1,
  "C" => 1,
  "D" => 2,
  "E" => 2,
  "F" => 2,

...etc., etc., etc., on and on and on for longer than you even want to know. What's a shorter and more elegant way of creating this hash without flipping its structure entirely?

Edit: Hey so, I realized there was a waaaay easier and more elegant way to do this than the answers given. Just declare an empty hash, then declare some arrays with the keys you want, then use a for statement to insert them into the array, like so:

du1 = ["A", "B", "C"]
du2 = ["D", "E", "F"]

dufactor = {}

for i in du1
  dufactor[i] = 1
end

for i in du740
  dufactor[i] = 2
end

...but the fact that nobody suggested that makes me, the extreme Ruby n00b, think that there must be a reason why I shouldn't do it this way. Performance issues?

Upvotes: 6

Views: 7779

Answers (5)

Christopher Smith
Christopher Smith

Reputation: 226

What about something like this:

du_factor = Hash.new
["A", "B", "C"].each {|ltr| du_factor[ltr] = 1}
["D", "E", "F"].each {|ltr| du_factor[ltr] = 2}

# Result:
du_factor # => {"A"=>1, "B"=>1, "C"=>1, "D"=>2, "E"=>2, "F"=>2}

Create an empty hash, then for each group of keys that share a value, create an array literal containing the keys, and use the array's '.each' method to batch enter them into the hash. Basically the same thing you did above with for loops, but it gets it done in three lines.

Upvotes: 1

spickermann
spickermann

Reputation: 107142

Combining Ranges with a case block might be another option (depending on the problem you are trying to solve):

case foo
when ('A'..'C') then 1
when ('D'..'E') then 2
# ...
end

Especially if you focus on your source code's readability.

Upvotes: 4

Nafaa Boutefer
Nafaa Boutefer

Reputation: 2359

keys = [%w(A B C), %w(D E F)]
values = [1,2] 
values.map!.with_index{ |value, idx| Array(value) * keys[idx].size }.flatten!
keys.flatten!
du_factor = Hash[keys.zip(values)]

Notice here that I used destructive methods (methods ending with !). this is important for performance and memory usage optimization.

Upvotes: 0

Cary Swoveland
Cary Swoveland

Reputation: 110755

How about:

vals_to_keys = {
  1 => [*'A'..'C'],
  2 => [*'D'..'F'],
  3 => [*'G'..'L'],
  4 => ['dog', 'cat', 'pig'],
  5 => [1,2,3,4]
}

vals_to_keys.each_with_object({}) { |(v,arr),h| arr.each { |k| h[k] = v } }
  #=> {"A"=>1, "B"=>1, "C"=>1, "D"=>2, "E"=>2, "F"=>2, "G"=>3, "H"=>3, "I"=>3,  
  #    "J"=>3, "K"=>3, "L"=>3, "dog"=>4, "cat"=>4, "pig"=>4, 1=>5, 2=>5, 3=>5, 4=>5}

Upvotes: 1

shirakia
shirakia

Reputation: 2409

keys = %w(A B C D E F)
values = [1, 1, 1, 2, 2, 2]
du_factor = Hash[*[keys, values].transpose.flatten]

If these will be more than 100, writing them down to a CSV file might be better.

Upvotes: 0

Related Questions