将键上的哈希数组分组并在另一个哈希键上附加嵌套数组

时间:2018-11-27 01:54:26

标签: ruby

如果该哈希键匹配,我需要将哈希数组简化为单个哈希。

my_array是一个哈希数组,每个哈希都有两个键:一个是活动记录对象,另一个是不同活动记录对象的数组,类似于:

my_array = [
  {
    first_hash_key: {id: 1, title: "my title"},
    second_hash_key: ["stuff", "more stuff", "more stuff"]
  },
  {
    first_hash_key: {id: 1, title: "my title"},
    second_hash_key: ["stuff 3", "uniq stuff 2"]
  },
  {
    first_hash_key: {id: 2, title: "my other title"},
    second_hash_key: ["interesting stuff", "uniq stuff"]
  }
]

我想通过first_hash_key[:id]组合哈希,将hash_key_two中的每个项目添加到数组中,而不是覆盖它们以获得:

my_array = [
  {
    first_hash_key: {id: 1, title: "my title"},
    second_hash_key: [
      ["stuff", "more stuff", "more stuff"],
      ["stuff 3", "uniq stuff 2"]
    ]
  },
  {
    first_hash_key: {id: 2, title: "my other title"},
    second_hash_key: ["interesting stuff", "uniq stuff"]
  }
]

我可以减少顶级数组和哈希,并使用merge,但是我丢失了哈希中的单个数组。

我也尝试过按id中的first_hash_key进行分组,然后像这样注入:

my_array.group_by{|h| h[:first_hash_key]}.map{|k,v| v.inject(:merge)}

同样,我丢失了second_hash_key中的数组。我只得到列出的最后一个数组。如果没有map,我会得到组中每个哈希的数组,但是顶层没有合并。

[
  {
    :first_hash_key=>{:id=>1, :title=>"my title"},
    :second_hash_key=>["stuff 3", "uniq stuff 2"]
  },
  {
    :first_hash_key=>{:id=>2, :title=>"my other title"}, 
    :second_hash_key=>["interesting stuff", "uniq stuff"]
  }
]

更新 正如sawa和cary所指出的那样,如果数据是一个数组或多个数组,最好猜测总是有数组数组,那么就没有必要猜测second_hash_key了。所需的输出是:

 [{:first_hash_key=>{:id=>1, :title=>"my title"}, 
   :second_hash_key=>[["stuff", "more stuff", "more stuff"], 
                      ["stuff 3", "uniq stuff 2"]]
 },
 {:first_hash_key=>{:id=>2, :title=>"my other title"}, 
 :second_hash_key=>[["interesting stuff", "uniq stuff"]]
 }]

2 个答案:

答案 0 :(得分:0)

它不是很漂亮,但是你去了:

my_array.
  group_by { |elem| elem[:first_hash_key] }.
  transform_values { |vals| vals.map { |val| val[:second_hash_key] } }.
  reduce([]) do |memo, (key, vals)|
    memo + [{first_hash_key: key, second_hash_key: vals}]
  end

返回:

[
  {
    :first_hash_key=>{:id=>1, :title=>"my title"},
    :second_hash_key=>[
      ["stuff", "more stuff", "more stuff"],
      ["stuff 3", "uniq stuff 2"]
    ]
  }, {
    :first_hash_key=>{:id=>2, :title=>"my other title"},
    :second_hash_key=>[
      ["interesting stuff", "uniq stuff"]
    ]
  }
]

如果您不清楚这是如何工作的,则应检查每行的结果,但要进行总结

  1. first_hash_key分组
  2. 调用transform_values以在second_hash_key处获取与每个first_hash_key值相对应的值

  3. 这时,您将哈希映射first_hash_key值映射到second_hash_key的所有对应值。现在只需reduce即可获得最终的数据结构。

这种group_by => transform_values => reduce的模式是我一直使用的东西,非常有用。我相信transform_values和ruby 2.5都可以在rails中使用。

答案 1 :(得分:0)

my_array.each_with_object({}) do |g,h|
  h.update(g[:first_hash_key][:id]=>g) { |_,o,n|
    o.merge(second_hash_key: [[*o[:second_hash_key]], n[:second_hash_key]]) }
end.values
  #=> [{:first_hash_key=>{:id=>1, :title=>"my title"},
  #     :second_hash_key=>[["stuff", "more stuff", "more stuff"],
  #                        ["stuff 3", "uniq stuff 2"]]},
  #    {:first_hash_key=>{:id=>2, :title=>"my other title"},
  #     :second_hash_key=>["interesting stuff", "uniq stuff"]}]

Hash#values的接收者是哈希:

{1=>{:first_hash_key=>{:id=>1, :title=>"my title"},
     :second_hash_key=>[["stuff", "more stuff", "more stuff"],
                        ["stuff 3", "uniq stuff 2"]]},
 2=>{:first_hash_key=>{:id=>2, :title=>"my other title"},
     :second_hash_key=>["interesting stuff", "uniq stuff"]}}

这使用Hash#update(也称为merge!)的形式,它采用一个块来确定两个合并的哈希中存在的键的值,这里的键是12。该块具有三个块变量:_等于公共密钥 1 o(“旧”)是正在构造的哈希中的键_的值,而n(“ new”)是哈希中的键_的值被合并到正在构建的哈希中。

如果[*o[:second_hash_key]]不是数组,则表达式o[:second_hash_key]会将o[:second_hash_key]转换为自身的数组,如果已经是数组,则将o[:second_hash_key]保留不变。例如[*1] #=> [1],而[*[1,2]] #=> [1,2]

返回值存在问题,因为:second_hash_key的值在一种情况下是一个数组数组,而在另一种情况下,它只是一个数组。因此,在随后的计算中,有必要确定每个值是数组的数组还是仅仅是数组,然后相应地采取措施。当然可以做到这一点,但是它是凌乱和丑陋的。最好使所有的值数组组成数组。我们可以这样做,如下。

my_array.each_with_object({}) do |g,h|
  h.update(g[:first_hash_key][:id]=>
    g.merge(second_hash_key: [g[:second_hash_key]])) { |_,o,n|
      o.merge(second_hash_key: o[:second_hash_key] + n[:second_hash_key]) }
end.values
  #=> [{:first_hash_key=>{:id=>1, :title=>"my title"},
  #     :second_hash_key=>[["stuff", "more stuff", "more stuff"],
  #                        ["stuff 3", "uniq stuff 2"]]},
  #    {:first_hash_key=>{:id=>2, :title=>"my other title"},
  #     :second_hash_key=>[["interesting stuff", "uniq stuff"]]}]

1下划线(有效的局部变量)用于公用密钥的作用是告知读者,块计算中未使用该下划线。