2009-04-16 56 views
5

我有一個紅寶石哈希看起來像這樣什麼對紅寶石哈希轉換爲數組

{ "stuff_attributes" => { 
    "1" => {"foo" => "bar", "baz" => "quux"}, 
    "2" => {"foo" => "bar", "baz" => "quux"} 
    } 
} 

的最佳方式,我希望把它變成一個哈希看起來像這樣

{ "stuff_attributes" => [ 
    { "foo" => "bar", "baz" => "quux"}, 
    { "foo" => "bar", "baz" => "quux"} 
    ] 
} 

我還需要保留鍵的數字順序,並且有可變數量的鍵。以上是超簡化的,但我在底部包含了一個實例。什麼是最好的方法來做到這一點?

PS

它也需要遞歸

至於遞歸去,這裏就是我們可以假設:

1)需要被操縱將匹配鍵/ _attributes $/ 2)哈希將有許多其他密鑰不匹配/ _attributes $/ 3)哈希中的密鑰將始終是一個數字 4)_attributes哈希可以在任何其他密鑰下的任何級別的哈希

這個散列實際上是控制器中創建動作的params散列。這是一個真正的例子,需要使用這個例程進行解析。

{ 
    "commit"=>"Save", 
    "tdsheet"=>{ 
    "team_id"=>"43", 
    "title"=>"", 
    "performing_org_id"=>"10", 
    "tdsinitneed_attributes"=>{ 
     "0"=>{ 
      "title"=>"", 
      "need_date"=>"", 
      "description"=>"", 
      "expected_providing_organization_id"=>"41" 
      }, 
     "1"=>{ 
      "title"=>"", 
      "need_date"=>"", 
      "description"=>"", 
      "expected_providing_organization_id"=>"41" 
      } 
     }, 
     "level_two_studycollection_id"=>"27", 
     "plan_attributes"=>{ 
      "0"=>{ 
       "start_date"=>"", "end_date"=>"" 
      } 
     }, 
     "dataitem_attributes"=>{ 
      "0"=>{ 
       "title"=>"", 
       "description"=>"", 
       "plan_attributes"=>{ 
        "0"=>{ 
         "start_date"=>"", 
         "end_date"=>"" 
         } 
        } 
       }, 
      "1"=>{ 
       "title"=>"", 
       "description"=>"", 
       "plan_attributes"=>{ 
        "0"=>{ 
         "start_date"=>"", 
         "end_date"=>"" 
         } 
        } 
       } 
      } 
     }, 
    "action"=>"create", 
    "studycollection_level"=>"", 
    "controller"=>"tdsheets" 
} 

回答

8

注意,這可能會很長,以測試是否所有按鍵都在轉換之前數...

def array_from_hash(h) 
    return h unless h.is_a? Hash 

    all_numbers = h.keys.all? { |k| k.to_i.to_s == k } 
    if all_numbers 
    h.keys.sort_by{ |k| k.to_i }.map{ |i| array_from_hash(h[i]) } 
    else 
    h.each do |k, v| 
     h[k] = array_from_hash(v) 
    end 
    end 
end 
4

如果我們可以假設,所有的按鍵都在乾淨轉換爲整數的事實串,下面應該工作:

# "hash" here refers to the main hash in your example, since you didn't name it 
stuff_hash = hash["stuff"] 
hash["stuff"] = stuff_hash.keys.sort_by {|key| key.to_i}.map {|key| stuff_hash[key]} 
+0

我該怎麼做遞歸?我忘了在提問中提到:\ – 2009-04-16 15:00:02

+0

您能舉出一個完整結構可以放在一起的例子嗎?遞歸需要多深,以及如何區分需要轉換的哈希和不需要的哈希(例如inner {「foo」=>「bar」,「baz」=>「quux」 })? – 2009-04-16 15:06:33

0

採取有點自由的,我張貼一個非常類似的代碼示例文森特羅伯特的。

這個是補丁Hash類與.to_array方法。

class Hash 
    def to_array(h = self) 
    return h unless h.is_a? Hash 
    if h.keys.all? { |k| k.to_i.to_s == k } # all keys are numbers so make an array. 
     h.keys.sort_by{ |k| k.to_i }.map{ |i| self.to_array(h[i]) } 
    else 
     h.each do |k, v| 
     h[k] = self.to_array(v) 
     end 
    end 
    end 
end 

這使得使用稍微更方便。