合并并合并一系列哈希

时间:2014-09-27 03:17:53

标签: ruby arrays hash enumerable

我正在尝试使用这个哈希值数组...

items => [{:name=>"item a", :count=>1, :contributors=>["51db6d58bd02861e96000004"]},
 {:name=>"item b", :count=>1, :contributors=>["51db6d58bd02861e96000004"]},
 {:name=>"item a", :count=>1, :contributors=>["51db6d58bd02861e96000004"]},
 {:name=>"item b", :count=>1, :contributors=>["51db6d58bd02861e96000004"]},
 {:name=>"item c", :count=>1, :contributors=>["51db6d58bd02861e96000004"]},
 {:name=>"item d", :count=>1, :contributors=>["51db6d58bd02861e96000004"]}]

获得如下所示的输出......

items => [{:name=>"item a", :count=>2, :contributors=>["51db6d58bd02861e96000004", "51db6d58bd02861e96000004"]},
     {:name=>"item b", :count=>2, :contributors=>["51db6d58bd02861e96000004, 51db6d58bd02861e96000004"]},
     {:name=>"item c", :count=>1, :contributors=>["51db6d58bd02861e96000004"]},
     {:name=>"item d", :count=>1, :contributors=>["51db6d58bd02861e96000004"]}]

我希望按名称进行分组并合并计数和贡献者,如上所示。我怎么做? Group_by,减少?有人可以发一个例子吗?

2 个答案:

答案 0 :(得分:2)

使用Enumerable#group_by

items = [
  {:name=>"item a", :count=>1, :contributors=>["51db6d58bd02861e96000004"]},
  {:name=>"item b", :count=>1, :contributors=>["51db6d58bd02861e96000004"]},
  {:name=>"item a", :count=>1, :contributors=>["51db6d58bd02861e96000004"]},
  {:name=>"item b", :count=>1, :contributors=>["51db6d58bd02861e96000004"]},
  {:name=>"item c", :count=>1, :contributors=>["51db6d58bd02861e96000004"]},
  {:name=>"item d", :count=>1, :contributors=>["51db6d58bd02861e96000004"]}
]
items.group_by { |h| h[:name] }.map { |key, hs|
  {:name => key,
   :count => hs.inject(0) { |c, h| c + h[:count] },
   :contributors => hs.map { |h| h[:contributors] }
  }
}

# => [{:name=>"item a", :count=>2,
#      :contributors=>[["51db6d58bd02861e96000004"], ["51db6d58bd02861e96000004"]]},
#     {:name=>"item b", :count=>2,
#      :contributors=>[["51db6d58bd02861e96000004"], ["51db6d58bd02861e96000004"]]},
#     {:name=>"item c", :count=>1, :contributors=>[["51db6d58bd02861e96000004"]]},
#     {:name=>"item d", :count=>1, :contributors=>[["51db6d58bd02861e96000004"]]}]

答案 1 :(得分:1)

我最初发布了另一个解决方案,但发现@falsetru已经发布了几乎相同的答案,所以它又回到了绘图板。实际上并不完全,因为对于这类问题,有两种常见的攻击线,所以我接着另一条攻击线。

def combine(items)
  items.each_with_object({}) do |g,h|
    h.update({ g[:name] => g }) do |k,ov,nv|
      { name: g[:name], count: (ov[:count] + nv[:count]),
        contributors: (ov[:contributors] + nv[:contributors]) }
    end
  end.values
end

这使用Hash#update(又名merge!)的形式,它采用一个块来确定被合并的两个哈希共享的每个键的值。

注意我允许:count使1:contributors以外的值具有包含多个值的值(数组)。

combine(items)
 #=>[{:name=>"item a", :count=>2,
 #    :contributors=>["51db6d58bd02861e96000004", "51db6d58bd02861e96000004"]},
 #   {:name=>"item b", :count=>2,
 #    :contributors=>["51db6d58bd02861e96000004", "51db6d58bd02861e96000004"]},
 #   {:name=>"item c", :count=>1, :contributors=>["51db6d58bd02861e96000004"]},
 #   {:name=>"item d", :count=>1, :contributors=>["51db6d58bd02861e96000004"]}]