Конвертировать хеш в другой хеш в Ruby - PullRequest
5 голосов
/ 14 марта 2012

У меня есть хеш строк

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

Я хочу преобразовать их в другой хеш, где ключ снова является ключом, но значение является либо строкой «active», либо пустой строкой, в зависимости от того,текущее имя контроллера содержит ключ.

Например, допустим, что текущим именем контроллера является «ClientsController».Результат, который я должен получить:

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

Вот как я сейчас это делаю:

active = {}

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

Я чувствую, что, хотя это работает, есть лучший способ сделать это вРубин, возможно используя inject или each_with_objects?

Ответы [ 4 ]

6 голосов
/ 14 марта 2012

ОБНОВЛЕНИЕ: я отправил другой ответ, который я думаю, что лучше для вашей ситуации. Я оставляю это без изменений, потому что оно само по себе имеет значение для подобных проблем.

Вот как я бы это сделал:

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

Вы можете запустить map для хэша, который получает пары ключ и значение в качестве входных данных для блока. Затем вы можете построить пары ключ / значение в массив в качестве вывода. Наконец, запуск Hash[*key_value_pairs.flatten] - хороший трюк, чтобы превратить его обратно в хеш. Это работает, потому что вы можете передать массив аргументов конструктору Hash[] для генерации хеша (Hash[1, 2, 3, 4] => { 1 => 2, 3 => 4 }). И flatten превращает пары ключ-значение в массив, а оператор * превращает массив в список аргументов.

Вот подробная версия на тот случай, если вы хотите более четко увидеть, что происходит:

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]

Обновление: это выше совместимо с ruby ​​1.8. Как отметил Андрей в комментариях:

В 1.9 вам не нужно * или сглаживать, так как Hash [] принимает массив значений ключа пар

4 голосов
/ 14 марта 2012

ПРИМЕЧАНИЕ: я уже ответил, но я публикую его как отдельный ответ, потому что он лучше для вашей конкретной ситуации, но мой другой ответ все еще имеет свои достоинства.

Так каквы вообще не используете значения хеша, вы можете использовать each_with_object:

navigable_objects.keys.each_with_object({}) { |k,h| h[k] = controller.controller_name.include?(k) ? 'active' : '' }

или более подробно:

new_hash = navigable_objects.keys.each_with_object({}) do |key, hash|
   hash[key] = controller.controller_name.include?(key) ? 'active' : ''
end

Если вашрезультат также основывался на значениях, тогда мое другое решение работало бы, тогда как это не сработало бы.

1 голос
/ 03 апреля 2017

Начиная с Ruby 2.0, существует to_h:

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

Не думаю, что это очень эффективно, но для маленьких хэшей это элегантный способ.

1 голос
/ 14 марта 2012

Есть много способов сделать это. Это просто способ, которым я бы это сделал.

С inject

active = navigable_objects.inject({}) do |h, obj|
  h[obj[0]] = controller.controller_name.include?(obj[0]) ? 'active' : ''
  h
end

Когда вы вызываете inject для хеша, блок передается вещью, в которую вы вводите (в данном случае хеш), и массивом с первым элементом, являющимся ключом, и последним элементом, являющимся значением.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...