2012-03-14 141 views
4

我有一個字符串轉換散列成另一種散列紅寶石

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

我想將它們轉換成另一種散列結果,其中的關鍵又是關鍵的哈希值,但值是字符串「活躍」或空字符串,具體取決於當前控制器名稱是否包含密鑰。

例如,可以說當前的控制器名稱是「ClientsController」。我應該得到的結果是:

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

這裏如何我目前做的是它:

active = {} 

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

我覺得,雖然這工作,有一個更好的辦法,這樣做在Ruby中可能使用inject或​​?

+0

我想指出的是,雖然還有其他解決方案(到目前爲止所發佈的所有解決方案都很好),但您原來的方式並沒有什麼特別的錯誤。 – 2012-03-14 01:06:57

+0

我覺得最讓我厭煩的是頂部的哈希聲明,而你的each_with_objects解決方案几乎可以解決這個問題! – link664 2012-03-14 01:12:47

回答

3

注意:我已經回答了,但我將其作爲一個單獨的答案發布,因爲它對您的具體情況更好,但我的其他答案仍然有自己的優點。

既然你不使用的哈希值可言,你可以使用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 

如果結果是基於值也是,那麼我的其他解決方案將工作,而這一個不會。

5

更新:我發佈了另一個我認爲更適合您的情況的答案。我將不再編輯這本書,因爲它有類似的問題。

這裏就是我想要做的方式:

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,你不需要*或壓扁的哈希[]取鍵值陣列 對

+3

在1.9中,你不需要'*'或'flatten'作爲['Hash []'](http://ruby-doc.org/core-1.9.3/Hash.html#method-c-5B -5D)採用鍵值數組對。 – 2012-03-14 00:50:24

1

有很多很多方法可以做到這一點:由於安德魯在評論中指出。這只是我做這件事的方式。

隨着inject

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

當在散列調用inject,塊被傳遞您正在注入的東西(在此情況下,散列),並與第一元件的陣列是所述鍵和最後一個元素是值。

+0

['each_with_object'](http://ruby-doc.org/core-1.9.3/Enumerable.html#method-i-each_with_object)在這裏更好,因爲您不必每次都錯誤地返回相同的散列引用時間':)' – 2012-03-14 00:58:07

+0

從未使用過'each_with_object',我只能'h.merge({key => val})' – Kyle 2012-03-14 00:59:24

+0

Nah; 'each_with_object' [輸入更多,比'inject'(或'tap')]更慢(http://phrogz.net/tap-vs-each_with_object)。 – Phrogz 2012-03-14 01:12:53

0

由於紅寶石2.0,有to_h:

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

我不認爲這是非常有效的,但對於小哈希它是一種優雅的方式。