我有一个看起来像这样的红宝石哈希
{ "stuff_attributes" => {
"1" => {"foo" => "bar", "baz" => "quux"},
"2" => {"foo" => "bar", "baz" => "quux"}
}
}
我想把它变成一个看起来像这样的哈希
{ "stuff_attributes" => [
{ "foo" => "bar", "baz" => "quux"},
{ "foo" => "bar", "baz" => "quux"}
]
}
我还需要保留键的数字顺序,并且键数可变。以上是超简化的,但我在底部包含了一个真实的例子。最好的方法是什么?
P.S
它还需要递归
就递归而言,这是我们可以假设的:
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"
}
答案 0 :(得分: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
答案 1 :(得分: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]}
答案 2 :(得分: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
它使用起来更方便。