将基于密钥后缀的平坦记录(哈希)数组拆分为规范化哈希的最佳方法是什么?

时间:2017-10-26 19:21:18

标签: ruby

转向的最佳(最佳效果)方式是什么:

csv_data = [
  {'id' => 1, 'foo_1' => 'a', 'bar_1' => 'b', 'foo_2' => 'c', 'bar_2' => 'd'},
  {'id' => 2, 'foo_1' => 'e', 'bar_1' => 'f', 'foo_2' => 'g', 'bar_2' => 'h'}
]

records = [
  {'id' => 1, 'foo' => 'a', 'bar' => 'b'},
  {'id' => 1, 'foo' => 'c', 'bar' => 'd'},
  {'id' => 2, 'foo' => 'e', 'bar' => 'f'},
  {'id' => 2, 'foo' => 'g', 'bar' => 'h'}
]

澄清:foo_100可能会有foo_1,但它会有所不同。

1 个答案:

答案 0 :(得分:1)

如果你总是使用长度为2的相同键,你可以写:

records = csv_data.flat_map do |row|
  [
    {id: row["id"], foo: row["foo_1"], bar: row["bar_1"]},
    {id: row["id"], foo: row["foo_2"], bar: row["bar_2"]},
  ]
end

适用于任何字段和长度的更通用的算法。我会在每一步添加数据,这可能会有所帮助:

records = csv_data.flat_map do |row|
  row
    # {"id"=>1, "foo_1"=>"a", "bar_1"=>"b", "foo_2"=>"c", "bar_2"=>"d"}
    .reject { |key, value| key == "id" }
    # {"foo_1"=>"a", "bar_1"=>"b", "foo_2"=>"c", "bar_2"=>"d"}
    .group_by { |key, value| key.split("_")[0] }
    # {"foo"=>[["foo_1", "a"], ["foo_2", "c"]], "bar"=>[["bar_1", "b"], ["bar_2", "d"]]}
    .map { |tag, key_values| [tag].product(key_values.map(&:last)) } 
    # [[["foo", "a"], ["foo", "c"]], [["bar", "b"], ["bar", "d"]]]
    .transpose
    # [[["foo", "a"], ["bar", "b"]], [["foo", "c"], ["bar", "d"]]]
    .map { |pairs| {"id" => row["id"]}.merge(pairs.to_h) }
    # [{"id"=>1, "foo"=>"a", "bar"=>"b"}, {"id"=>1, "foo"=>"c", "bar"=>"d"}]
end