如何减少"具有重复键到嵌套哈希的哈希数组?

时间:2016-09-08 19:01:58

标签: arrays ruby hash

  

注意:有关此问题的一些类似问题,例如here   和here,但似乎没有一个像我正在寻找的那样。

假设我有一系列像这样的哈希:

arr_with_dup_hsh_keys = [
  { foo: "dup", bar: 1 },
  { foo: "dup", bar: 2 },
  { foo: "dup", bar: 3 },
  { foo: "dup", bar: 4 },
  { foo: "dup", bar: 5 }
]

如何将其减少到这个?

{ foo: "dup", bars: [1, 2, 3, 4, 5] }

如果foo有不同的值,该怎么办?

arr_with_dup_hsh_keys = [
  { foo: "dup",  bar: 1 },
  { foo: "dup",  bar: 2 },
  { foo: "soup", bar: 3 },
  { foo: "dup",  bar: 4 },
  { foo: "soup", bar: 5 }
]

3 个答案:

答案 0 :(得分:4)

def combine(arr)
  arr.group_by {|g|g[:foo]}.map {|_,a|{foo: a.first[:foo], bar: a.map {|g| g[:bar]}}}
end

combine arr_with_dup_hsh_keys
  #=> [{:foo=>"dup", :bar=>[1, 2, 3, 4, 5]}]

arr_with_dup_hsh_keys1 = [
  { foo: "dup",  bar: 1 },
  { foo: "dup",  bar: 2 },
  { foo: "soup", bar: 3 },
  { foo: "dup",  bar: 4 },
  { foo: "soup", bar: 5 }
]

combine arr_with_dup_hsh_keys1
  #=> [{:foo=>"dup", :bar=>[1, 2, 4]}, {:foo=>"soup", :bar=>[3, 5]}] 

请参阅Enumerable#group_by并注意

arr_with_dup_hsh_keys1.group_by { |g| g[:foo] }
 #=> {"dup"=> [{:foo=>"dup", :bar=>1}, {:foo=>"dup", :bar=>2},
 #             {:foo=>"dup", :bar=>4}],
 #    "soup"=>[{:foo=>"soup", :bar=>3}, {:foo=>"soup", :bar=>5}]}

您也可以写下以下内容。

def combine(arr)
  arr.each_with_object({}) do |g,h|
    f = g.merge(bar: [g[:bar]])
    h.update(f[:foo]=>f) { |_,o,n| { foo: o[:foo], bar: o[:bar]+n[:bar] } }
  end.values
end

combine arr_with_dup_hsh_keys1
  #=> [{:foo=>"dup", :bar=>[1, 2, 4]}, {:foo=>"soup", :bar=>[3, 5]}] 

这使用Hash#update(aka merge!)的形式,它使用一个块来确定合并的两个哈希中存在的键的值。请参阅文档以获取对三个块变量的解释(第一个是公共密钥,我用下划线表示它代表它未在块计算中使用)。

答案 1 :(得分:1)

如果您的数据非常简单,那么您可以按照自己的意愿行事:

{ foo: "dup",
  bars: arr_with_dup_hsh_keys.map {|hsh| hsh[:bar] }
}

答案 2 :(得分:1)

这就是我的想法:

a = [
  { foo: "dup", bar: 1 },
  { foo: "dup", bar: 2 },
  { foo: "dup", bar: 3 },
  { foo: "dup", bar: 4 },
  { foo: "dup", bar: 5 }
]

h = {}
a.map(&:keys).uniq.flatten.each_with_index do |key, idx|
  h[key] = a.map(&:values).collect { |a| a[idx]}.uniq
end
h
#=> {:foo=>["dup"], :bar=>[1, 2, 3, 4, 5]}