groupby数组哈希到数组哈希数组?

时间:2015-01-29 01:58:08

标签: ruby arrays

我正在尝试用ruby中的数据操作。

鉴于此哈希数组

peepz = [
{
  :name => 'ted',
  :phone => '555-1234',
  :color => 'red'
},
{
  :name => 'bill',
  :phone => '555-2222',
  :color => 'green'
},
{
  :name => 'ted',
  :phone => '555-3333',
  :color => 'orange'
},
{
  :name => 'dan',
  :phone => '555-7777',
  :color => 'violet'
},
{
  :name => 'ted',
  :phone => '555-4444',
  :color => 'yellow'
},
{
  :name => 'dan',
  :phone => '555-6666',
  :color => 'orange'
}
];

我希望这个输出

peepz2 = [
  {
    :name => 'ted'
    :phone => ['555-1212','555-3333','555-4444']
    :color => ['red','orange','yellow']
  },
  {
    :name => 'bill'
    :phone => ['555-2222']
    :color => ['green']
  },
  {
    :name => 'dan'
    :phone => ['555-7777','555-6666']
    :color => ['violet','orange']
  },
]

这是我到目前为止所拥有的。

def groupbyer ( peepz, *fields )
    peepz.groupby do |peep|
      key = ''
      fields.each do |field|
        key += peep[field].to_s
      end
    end.each do |group|
      ????
    end
end

groupbyer(peepz, :name)

此方法必须概括。它不能硬编码peepz的字段

完成此任务的红宝石方法是什么?

2 个答案:

答案 0 :(得分:4)

peepz
.group_by{|h| h[:name]}.values
.map{|a| a.inject{|h1, h2| h1.merge(h2){|k, v1, v2| k == :name ? v1 : [*v1, v2]}}}

答案 1 :(得分:1)

另一种方法使用Hash#update(aka merge!)的形式,它使用一个块来确定合并的两个哈希中存在的键的值:

<强>代码

def peep_merge(peepz)
  peepz.each_with_object({}) { |g,h|
         h.update(g[:name]=>(g.merge(g) { |*_,v|
           [v] })) { |_,oh,nh| oh.merge(nh) { |_,ov,nv| ov+nv } } }
       .values
       .each { |h| h[:name] = h[:name].first }
end

示例

对于问题中给出的peepz

peep_merge(peepz)
  #=> [{:name=>"ted",                   
  #     :phone=>["555-1234", "555-3333", "555-4444"],
  #     :color=>["red", "orange", "yellow"]},
  #    {:name=>"bill",
  #     :phone=>["555-2222"],
  #     :color=>["green"]},
  #    {:name=>"dan",
  #     :phone=>["555-7777", "555-6666"],
  #     :color=>["violet", "orange"]}]

<强>解释

a = peepz.each_with_object({}) { |g,h|
      h.update(g[:name]=>(g.merge(g) { |*_,v|
        [v] })) { |_,oh,nh| oh.merge(nh) { |_,ov,nv| ov+nv } } }
  #=> {"ted" =>{:name=>["ted", "ted", "ted"],
  #             :phone=>["555-1234", "555-3333", "555-4444"],
  #             :color=>["red", "orange", "yellow"]},
  #    "bill"=>{:name=>["bill"],
  #             :phone=>["555-2222"],
  #             :color=>["green"]},
  #    "dan" =>{:name=>["dan", "dan"], 
  #             :phone=>["555-7777", "555-6666"],
  #             :color=>["violet", "orange"]}} 
b = a.values
  #=>         [{:name =>["ted", "ted", "ted"],
  #             :phone=>["555-1234", "555-3333", "555-4444"],
  #             :color=>["red", "orange", "yellow"]},
  #            {:name =>["bill"],
  #             :phone=>["555-2222"],
  #             :color=>["green"]},
  #            {:name =>["dan", "dan"],
  #             :phone=>["555-7777", "555-6666"],
  #             :color=>["violet", "orange"]}]

最后,要更正:name键的值:

b.each { |h| h[:name] = h[:name].first }

提供上面示例中显示的结果。