Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert a hash into another hash in Ruby

I have a hash of strings

navigable_objects = { 'Dashboard' => root_path,
                      'Timesheets' => timesheets_path,
                      'Clients' => clients_path,
                      'Projects' => projects_path, 
                    }

I want to convert them into another hash where the key is again the key, but the value is either the string 'active' or empty string depending on whether the current controller name contains the key.

For example, lets say that the current controller name is "ClientsController". The result I should get is:

{ 'Dashboard' => '',
  'Timesheets' => '',
  'Clients' => 'active',
  'Projects' => ''
}

Here is how I am currently doing it:

active = {}

navigable_objects.each do |name, path|
  active[name] = (controller.controller_name.include?(name)) ? 'active' : '')
end 

I feel that while this works, there is a better way to do this in Ruby, possibly using inject or each_with_objects?

like image 631
dnatoli Avatar asked Mar 14 '12 00:03

dnatoli


People also ask

How do you combine hashes in Ruby?

We can merge two hashes using the merge() method. When using the merge() method: Each new entry is added to the end. Each duplicate-key entry's value overwrites the previous value.

How do you add hash to hash?

Merge two hashes On of the ways is merging the two hashes. In the new hash we will have all the key-value pairs of both of the original hashes. If the same key appears in both hashes, then the latter will overwrite the former, meaning that the value of the former will disappear. (See the key "Foo" in our example.)

How do you add a value to an existing hash in Ruby?

You might get your key and value from user input, so you can use Ruby . to_sym can convert a string to a symbol, and . to_i will convert a string to an integer.

How do you make hash hash in Ruby?

In Ruby you can create a Hash by assigning a key to a value with => , separate these key/value pairs with commas, and enclose the whole thing with curly braces.


1 Answers

UPDATE: I posted another answer that I think is better for your situation. I'm leaving this one un-edited though because it has merit on its own for similar problems.

Here's the way I'd do it:

Hash[*navigable_objects.map{ |k,v| [k, controller.controller_name.include?(k) ? 'active' : ''] }.flatten]

You can run map on a hash that gets key and value pairs as input to the block. Then you can construct pairs of key/values into arrays as the output. Finally, Running Hash[*key_value_pairs.flatten] is a nice trick to turn it back into a hash. This works because you can pass an array of arguments to the Hash[] constructor to generate a hash (Hash[1, 2, 3, 4] => { 1 => 2, 3 => 4 }). And flatten turns the key value pairs into an array, and * operator turns an array into a list of arguments.

Here's a verbose version in case you want to see more clearly what's going on:

key_value_pairs = navigable_objects.map do |key, value|
    new_value = controller.controller_name.include?(k) ? 'active' : ''
    [key, new_value]
end

new_hash = Hash[*key_value_pairs.flatten]

Update: This above is compatible with ruby 1.8. As Andrew pointed out in the comments:

In 1.9 you don't need the * or flatten as Hash[] takes key-value array pairs

like image 191
Ben Lee Avatar answered Oct 29 '22 04:10

Ben Lee