2009-04-16 55 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 

这使得使用稍微更方便。