这是我在Rails params中获得的内容:
obj => {
"raw_data" =>
[
{ "id" => "1", "name" => "John Doe" },
{ "id" => "2", "name" => "Jane Doe" }
]
}
我必须转换成以下对象:
obj => {
"data" =>
{
"1" => { "name" => "John Doe" },
"2" => { "name" => "Jane Doe" }
}
}
这是我目前工作的代码:
if obj[:raw_data]
obj[:data] = Hash.new
obj[:raw_data].each do |raw|
obj[:data][raw[:id]] = Hash.new
obj[:data][raw[:id]][:name] = raw[:name] if raw[:name].present?
end
end
obj.delete(:raw_data)
有没有办法重构它?也许使用map
。请注意,数据结构也必须从数组更改为哈希。
感谢您的任何提示。
答案 0 :(得分:2)
这是一种方式:
obj = {
"raw_data" => [
{ "id" => "1", "name" => "John Doe" },
{ "id" => "2", "name" => "Jane Doe" }
]
}
data = obj["raw_data"].map do |item|
item = item.dup
[ item.delete('id'), item ]
end
obj2 = { "data" => data.to_h }
# => { "data" =>
# { "1" => { "name" => "John Doe" },
# "2" => { "name" => "Jane Doe" }
# }
# }
如果您正在使用Rails,可以使用ActiveSupport中的Hash#except
方法使其更简洁:
data = obj["raw_data"].map {|item| [ item["id"], item.except("id") ] }
obj2 = { "data" => data.to_h }
答案 1 :(得分:1)
d = obj[:raw_data]
keys = d.map { |h| h["id"] }
values = d.map { |h| h.except("id") }
Hash[ keys.zip(values) ]
# or as a oneliner
Hash[ d.map { |h| h["id"] }.zip(d.map { |h| h.except("id")) ]
# => {"1"=>{"name"=>"John Doe"}, "2"=>{"name"=>"Jane Doe"}}
这种特殊的Hash[]
语法允许您从键数组和值数组创建哈希。
Hash.except(*args)
是散列类的ActiveSupport添加,它返回一个没有黑名单中的键的新密钥。
答案 2 :(得分:0)
在rails中,您可以使用index_by
方法:
obj = {raw_data: [{id: "1", name: "John Doe"}, {id: "2", name: "Jane Doe"}]}
obj2 = {
data: obj[:raw_data].index_by {|h| h[:id]}.each {|_,h| h.delete(:id)}
} #=> {:data=>{"1"=>{:name=>"John Doe"}, "2"=>{:name=>"Jane Doe"}}}
这样做的一个缺点就是它会通过删除id属性来修改原始数据。如果这是不可接受的,这里有修改,安全版本:
obj2 = {
data: obj[:raw_data].map(&:clone).index_by {|h| h[:id]}.each {|_,h| h.delete(:id)}
} #=> {:data=>{"1"=>{:name=>"John Doe"}, "2"=>{:name=>"Jane Doe"}}}
答案 3 :(得分:0)
我认为你的意思是obj = {...}
而不是obj => {...}
,因为后者不是有效的对象。如果是这样的话:
{ "data" => obj["raw_data"].each_with_object({}) { |g,h|
h[g["id"]] = g.reject { |k,_| k == "id" } } }
#=> {"data"=>{"1"=>{"name"=>"John Doe"}, "2"=>{"name"=>"Jane Doe"}}}
如果obj
可以变异,你可以简化一下:
{ "data" => obj["raw_data"].each_with_object({}) { |g,h| h[g.delete("id")]=g } }
作为一种改进的非变异解决方案,@ Max提出了一个Rails'调整:
{ "data" => obj["raw_data"].each_with_object({}) { |g,h| h[g["id"]] = g.except("id") } }
这对我来说很好看,但由于我不了解铁轨,我从表面上看这个建议。