我有一个字符串哈希
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中有更好的方法可以使用inject
或each_with_objects
吗?
答案 0 :(得分:6)
更新:我发布了另一个我认为更适合您情况的答案。我将离开这个未经编辑的版本,因为它本身就有类似问题的优点。
以下是我的方式:
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 []接受键值数组 对
答案 1 :(得分:4)
注意:我已经回答了,但我将此作为一个单独的答案发布,因为它对您的具体情况更好,但我的另一个答案仍然有其自身的优点。
由于您根本没有使用哈希值,可以使用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
如果您的结果也基于这些值,那么我的其他解决方案就可以了,而这个不会。
答案 2 :(得分:1)
有许多方法可以实现这一目标。这就是我这样做的方式。
使用inject
active = navigable_objects.inject({}) do |h, obj|
h[obj[0]] = controller.controller_name.include?(obj[0]) ? 'active' : ''
h
end
当你在哈希上调用inject
时,块会传递你注入的东西(在这种情况下是一个哈希)和一个数组,第一个元素是键,最后一个元素是值。
答案 3 :(得分:1)
从Ruby 2.0开始,有to_h:
navigable_objects.map do |name, path|
[name, controller.controller_name.include?(name)) ? 'active' : '']
end.to_h
我认为它非常有效,但对于小哈希来说,它是一种优雅的方式。