Nick Osborn Nick Osborn - 5 months ago 8
Ruby Question

Collecting hash entries with identical values

I have an array that looks like below

unorganized_array = [{:identifier => '1', :groupinfo => [
{:color => 'blue', :texture => 'soft'}]},
{:identifier => '1', :groupinfo => [
{:color => 'green', :texture => 'hard'}]},
{{:identifier => '2', :groupinfo =>
[{:color => 'red', :texture => 'spiky'}]}


I want to collect all the entries with the same
:identifier
into that identifier's
:groupinfo
. This has an extra
:identifier => '2'
group compared to the previous example:

organized_array = [{:identifier => '1', :groupinfo => [
{:color => 'blue', :texture => 'soft'},
{:color => 'green', :texture => 'hard'}]},
{:identifier => '2', :groupinfo =>
[{:color => 'red', :texture => 'spiky'},
{:color => 'gray', :texture => 'squishy}]}]


I feel like
Hash#merge
and
Hash#inject
would be useful here but I'm unsure as to how to implement them.

I'm making unorganized_array from an array that looks like

original_array = [['blue', 'soft', '1', 'irrelevant'], ['green','hard','1','irrelevant1'],
['red','spiky','2','irrelevant2']]


perhaps there is a better method than going from original_array -> unorganized_array -> organized_array?

so far I've been trying to use #map and #each with for loops to group them together, i.e.

unorganized_array = original_array.map! do |first, second, third, fourth|
{:identifier => third, :groupinfo => [{:color => first, :texture => second}]}
end

Answer
unorganized_array.map(&:dup)
                 .group_by { |e| e.delete(:identifier) }
                 .map { |k, v| [k, v.flat_map { |h| h[:groupinfo] } ] }
                 .map { |k, v| { identifier: k, groupinfo: v } }

The above gives on the input shown:

#⇒ [ { :groupinfo => [ 
#         { :color => "blue", :texture => "soft" },
#         { :color => "green", :texture => "hard" } ],
#      :identifier => "1" },
#    { :groupinfo => [
#         { :color => "red", :texture => "spiky" } ],
#      :identifier => "2" } ]
Comments