在Ruby中将哈希转换为另一个哈希

5

我有一个字符串哈希表

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 

我感觉虽然这样做可以实现,但在Ruby中有更好的方式,可能使用injecteach_with_object


我想指出的是,虽然有其他的解决方案(所有发布的方案到目前为止都很好),但你最初的方法并没有什么特别错误的地方。 - Ben Lee
我认为最让我烦恼的是顶部的哈希声明,而你的each_with_objects解决方案基本上解决了这个问题! - dnatoli
4个回答

7
< p >更新:我发了另一个答案,我认为对于你的情况更好。不过,我保留这个答案未编辑,因为它本身对于类似问题是有价值的。

这是我会做的方法:

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版本中,您不需要使用*或flatten函数,因为Hash[]可以直接接收键值对数组。

3
在 Ruby 1.9 中,你不需要使用 *flatten,因为 Hash[] 可以接受键值对数组。 - Andrew Marshall

5

注意:我已经回答过,但我将其发布为单独的答案,因为它更适合您的特定情况,但我的其他答案仍然有其价值。

由于您根本没有使用哈希的值,您可以使用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

如果你的结果也基于这些值,那么我的另一个解决方案会有效,而这个则不会。

3
自 Ruby 2.0 版本开始,新增了 to_h 方法:
navigable_objects.map do |name, path|
  [name, controller.controller_name.include?(name)) ? 'active' : '']
end.to_h

我认为这种方法效率不高,但对于小的哈希表来说是一种优雅的方式。


1

有很多种方法可以实现这个。这只是我会做的方式。

使用 inject

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

当你在哈希表上调用inject函数时,该块将传递你要注入的对象(在本例中为哈希表)和一个数组,其中第一个元素是键,最后一个元素是值。

在这里使用each_with_object更好,因为您不必每次错误地返回相同的哈希引用 :)each_with_object - Andrew Marshall
从来没有使用each_with_object,我只能使用h.merge({key => val}) - Kyle
不用了;each_with_objectinject(或tap更费力且速度较慢 - Phrogz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接