Search code examples
rubyarrayshashenumerable

Merge and consolidate an array of hashes


I am trying to take this array of hash values...

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"]}]

And get an output that looks like the following...

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"]}]

I want to group by name and consolidate the count, and contributors as illustrated above. How do I do that? Group_by, reduce? Can someone post an example?


Solution

  • Using 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"]]}]