Ruby on rails 如何使用ruby水平转换json数据

Ruby on rails 如何使用ruby水平转换json数据,ruby-on-rails,json,ruby,rubygems,jruby,Ruby On Rails,Json,Ruby,Rubygems,Jruby,我希望使用ruby水平转换json数据。我的json数据如下所示 [ { "ID": "ID001", "Type": "Type1", "Week": "W1", "Count": 1 }, { "ID": "ID001", "Type"

我希望使用ruby水平转换json数据。我的json数据如下所示

[
  {
    "ID": "ID001",
    "Type": "Type1",
    "Week": "W1",
    "Count": 1
  },
  {
    "ID": "ID001",
    "Type": "Type1",
    "Week": "W2",
    "Count": 2
  },
  {
    "ID": "ID001",
    "Type": "Type2",
    "Week": "W1",
    "Count": 2
  },
  {
    "ID": "ID001",
    "Type": "Type2",
    "Week": "W2",
    "Count": 3
  },
  {
    "ID": "ID001",
    "Type": "Type3",
    "Week": "W1",
    "Count": 3
  },
  {
    "ID": "ID001",
    "Type": "Type3",
    "Week": "W2",
    "Count": 4
  }
]
[
  {
    "ID": "ID001",
    "Type": "Type1",
    "W1": 1,
    "W2": 2
  },
  {
    "ID": "ID001",
    "Type": "Type2",
    "W1": 2,
    "W2": 3
  },
  {
    "ID": "ID001",
    "Type": "Type3",
    "W1": 3,
    "W2": 4
  }
]
我的预期结果是这样的

[
  {
    "ID": "ID001",
    "Type": "Type1",
    "Week": "W1",
    "Count": 1
  },
  {
    "ID": "ID001",
    "Type": "Type1",
    "Week": "W2",
    "Count": 2
  },
  {
    "ID": "ID001",
    "Type": "Type2",
    "Week": "W1",
    "Count": 2
  },
  {
    "ID": "ID001",
    "Type": "Type2",
    "Week": "W2",
    "Count": 3
  },
  {
    "ID": "ID001",
    "Type": "Type3",
    "Week": "W1",
    "Count": 3
  },
  {
    "ID": "ID001",
    "Type": "Type3",
    "Week": "W2",
    "Count": 4
  }
]
[
  {
    "ID": "ID001",
    "Type": "Type1",
    "W1": 1,
    "W2": 2
  },
  {
    "ID": "ID001",
    "Type": "Type2",
    "W1": 2,
    "W2": 3
  },
  {
    "ID": "ID001",
    "Type": "Type3",
    "W1": 3,
    "W2": 4
  }
]

请让我知道我们如何用Ruby做到这一点。这更像是通过引用group by键类型将值合并到键中的情况。就像我们在sql查询中所做的那样,在函数链接非变异样式中优化可读性:

散列=[
{ID:“ID001”,键入:“Type1”,周:“W1”,计数:1},
{ID:“ID001”,键入:“Type1”,周:“W2”,计数:2},
{ID:“ID001”,键入:“Type2”,周:“W1”,计数:2},
{ID:“ID001”,键入:“Type2”,周:“W2”,计数:3},
{ID:“ID001”,键入:“Type3”,周:“W1”,计数:3},
{ID:“ID001”,键入:“Type3”,周:“W2”,计数:4}
]
分组=hashes.group_by do|hash|
hash.slice(:ID,:Type)
终止
值_transposed=grouped.transform_值do | grp|
grp.map{| h |[h[:Week].to_sym,h[:Count]]}.to_h
终止
values_transposed.map{| grp,values | grp.merge(values)}
# => [
#{:ID=>“ID001”,:Type=>“Type1”,:W1=>1,:W2=>2},
#{:ID=>“ID001”,:Type=>“Type2”,:W1=>2,:W2=>3},
#{:ID=>“ID001”,:Type=>“Type3”,:W1=>3,:W2=>4}]

优化功能链接非变异样式的可读性:

散列=[
{ID:“ID001”,键入:“Type1”,周:“W1”,计数:1},
{ID:“ID001”,键入:“Type1”,周:“W2”,计数:2},
{ID:“ID001”,键入:“Type2”,周:“W1”,计数:2},
{ID:“ID001”,键入:“Type2”,周:“W2”,计数:3},
{ID:“ID001”,键入:“Type3”,周:“W1”,计数:3},
{ID:“ID001”,键入:“Type3”,周:“W2”,计数:4}
]
分组=hashes.group_by do|hash|
hash.slice(:ID,:Type)
终止
值_transposed=grouped.transform_值do | grp|
grp.map{| h |[h[:Week].to_sym,h[:Count]]}.to_h
终止
values_transposed.map{| grp,values | grp.merge(values)}
# => [
#{:ID=>“ID001”,:Type=>“Type1”,:W1=>1,:W2=>2},
#{:ID=>“ID001”,:Type=>“Type2”,:W1=>2,:W2=>3},
#{:ID=>“ID001”,:Type=>“Type3”,:W1=>3,:W2=>4}]
请参阅(也称为“合并”)


步骤如下

enum = arr.each_with_object({})
  #=> #<Enumerator: [{:ID=>"ID001",..., :Count=>2}, {:ID=>"ID001",...,
  #     :Count=>2},...,{:ID=>"ID001",..., :Count=>4}]:
  #        each_with_object({})> 
然后执行块计算

key = g[:Type]
  #=> "Type1" 

h[key] ||= {}
h["Type1"] = h["Type1"] || {}
h["Type1"] = nil || {}
h["Type1"] = {}

h #=> { "Type1"=>{} }

h[key].update(ID: g[:ID], Type: key, g[:Week].to_sym=>g[:Count])
h["Type1"].update(ID: "ID001", Type: "Type1", "W1".to_sym=>1)
{}.update(ID: "ID001", Type: "Type1", :W1=>1)
  #=> {:ID=>"ID001", :Type=>"Type1", :W1=>1} 
h #=> {:ID=>"ID001", :Type=>"Type1", :W1=>1}
然后,下一个元素由
enum
生成并传递给块

g,h = enum.next
  #=> [{:ID=>"ID001", :Type=>"Type1", :Week=>"W2", :Count=>2},
  #    {"Type1"=>{:ID=>"ID001", :Type=>"Type1", :W1=>1}} 
g #=> {:ID=>"ID001", :Type=>"Type1", :Week=>"W2", :Count=>2} 
h #=> {"Type1"=>{:ID=>"ID001", :Type=>"Type1", :W1=>1} 

key = g[:Type]
  #=> "Type1" 
h[key] ||= {}
h["Type1"] = h["Type1"] || {}
h["Type1"] = {:ID=>"ID001", :Type=>"Type1", :W1=>1} || {}
h["Type1"] = {:ID=>"ID001", :Type=>"Type1", :W1=>1}
h #=> {"Type1"=>{:ID=>"ID001", :Type=>"Type1", :W1=>1}} (no change)

h[key].update(ID: g[:ID], Type: key, g[:Week]=>g[:Count])
h["Typt1"].update(ID: g[:ID], Type: key, g[:Week].to_sym=>g[:Count])
{:ID=>"ID001", :Type=>"Type1", "W1"=>1}}.update(ID: g[:ID], Type: key,
  g[:Week].to_sym=>g[:Count])
  #=> {:ID=>"ID001", :Type=>"Type1", :W1=>1, :W2=>2} 
h #=> {"Type1"=>{:ID=>"ID001", :Type=>"Type1", :W1=>1, :W2=>2}} 
对于剩余的四个元素中的每一个元素,
enum
生成并传递到块,然后
enum
返回散列:

{"Type1"=>{:ID=>"ID001", :Type=>"Type1", :W1=>1, :W2=>2},
 "Type2"=>{:ID=>"ID001", :Type=>"Type2", :W1=>2, :W2=>3},
 "Type3"=>{:ID=>"ID001", :Type=>"Type3", :W1=>3, :W2=>4}}
最后一步是使用从该散列中提取值

请参阅(也称为“合并”)


步骤如下

enum = arr.each_with_object({})
  #=> #<Enumerator: [{:ID=>"ID001",..., :Count=>2}, {:ID=>"ID001",...,
  #     :Count=>2},...,{:ID=>"ID001",..., :Count=>4}]:
  #        each_with_object({})> 
然后执行块计算

key = g[:Type]
  #=> "Type1" 

h[key] ||= {}
h["Type1"] = h["Type1"] || {}
h["Type1"] = nil || {}
h["Type1"] = {}

h #=> { "Type1"=>{} }

h[key].update(ID: g[:ID], Type: key, g[:Week].to_sym=>g[:Count])
h["Type1"].update(ID: "ID001", Type: "Type1", "W1".to_sym=>1)
{}.update(ID: "ID001", Type: "Type1", :W1=>1)
  #=> {:ID=>"ID001", :Type=>"Type1", :W1=>1} 
h #=> {:ID=>"ID001", :Type=>"Type1", :W1=>1}
然后,下一个元素由
enum
生成并传递给块

g,h = enum.next
  #=> [{:ID=>"ID001", :Type=>"Type1", :Week=>"W2", :Count=>2},
  #    {"Type1"=>{:ID=>"ID001", :Type=>"Type1", :W1=>1}} 
g #=> {:ID=>"ID001", :Type=>"Type1", :Week=>"W2", :Count=>2} 
h #=> {"Type1"=>{:ID=>"ID001", :Type=>"Type1", :W1=>1} 

key = g[:Type]
  #=> "Type1" 
h[key] ||= {}
h["Type1"] = h["Type1"] || {}
h["Type1"] = {:ID=>"ID001", :Type=>"Type1", :W1=>1} || {}
h["Type1"] = {:ID=>"ID001", :Type=>"Type1", :W1=>1}
h #=> {"Type1"=>{:ID=>"ID001", :Type=>"Type1", :W1=>1}} (no change)

h[key].update(ID: g[:ID], Type: key, g[:Week]=>g[:Count])
h["Typt1"].update(ID: g[:ID], Type: key, g[:Week].to_sym=>g[:Count])
{:ID=>"ID001", :Type=>"Type1", "W1"=>1}}.update(ID: g[:ID], Type: key,
  g[:Week].to_sym=>g[:Count])
  #=> {:ID=>"ID001", :Type=>"Type1", :W1=>1, :W2=>2} 
h #=> {"Type1"=>{:ID=>"ID001", :Type=>"Type1", :W1=>1, :W2=>2}} 
对于剩余的四个元素中的每一个元素,
enum
生成并传递到块,然后
enum
返回散列:

{"Type1"=>{:ID=>"ID001", :Type=>"Type1", :W1=>1, :W2=>2},
 "Type2"=>{:ID=>"ID001", :Type=>"Type2", :W1=>2, :W2=>3},
 "Type3"=>{:ID=>"ID001", :Type=>"Type3", :W1=>3, :W2=>4}}

最后一步是从这个散列中提取值。

用类似的答案给我一个重拳出击。FWIW,一个简单的基准测试表明,这比
groupby
方法的效率要高一点。@rmlockerd,正如您可能注意到的,这相对有效的原因是,在每一步,一个新的键值对被添加到一个散列中,该散列是
h
的key
k
的值;该散列(
h[k]
)不会被修改<例如,如果期望的返回值是一个包含散列的数组,例如
{:ID=>“ID001”,Type=>“Type1”,w=>{“W1”=>1,“W2”=>2}
,则code>groupby和散列的其他用法在性能上非常相似。在这种情况下,hash
h[k]
必须在每一步都进行修改,而不仅仅是添加到中。FWIW,一个简单的基准测试表明,这比
groupby
方法的效率要高一点。@rmlockerd,正如您可能注意到的,这相对有效的原因是,在每一步,一个新的键值对被添加到一个散列中,该散列是
h
的key
k
的值;该散列(
h[k]
)不会被修改<例如,如果期望的返回值是一个包含散列的数组,例如
{:ID=>“ID001”,Type=>“Type1”,w=>{“W1”=>1,“W2”=>2}
,则code>groupby和散列的其他用法在性能上非常相似。在这种情况下,hash
h[k]
必须在每一步进行修改,而不仅仅是添加到。这看起来很好,也很完美。但我需要的是json数据,而不是哈希。我尝试使用hashes=JSON.parse(JSON)并注释您的hashes变量,我得到了以下错误:“nil:NilClass的undefined method`to_sym'(nomethoderor如果您以JSON字符串开头,那么您将需要与我使用的哈希格式相同的方法(这是您在问题中粘贴的格式),无需任何修改即可使用我的代码。首先,默认情况下,
JSON.parse
会创建字符串键,但您可以执行
JSON.parse(JSON\u String,Symbol\u names:true)
来获取符号键。这看起来很好,也很完美。但我需要的是JSON数据,而不是哈希。我尝试了哈希=JSON.parse(JSON)在注释hashes变量时,我得到了一个错误:nil:NilClass的“undefined method`to_sym”(nomethoderRor如果您以JSON字符串开头,那么您将需要与我使用的哈希格式相同的方法(这是您在问题中粘贴的),无需任何修改即可使用我的代码。首先,默认情况下,
JSON.parse
会创建字符串键,但您可以执行
JSON.parse(JSON\u String,Symbol\u names:true)
来获取符号键。