Manav
Manav

Reputation: 679

Rails group array of hash by a key

I have the array of hash like this:

[{"1"=>{:name=>"Miss Sneaky", :race_no=>"2", :drawn_box=>"2"}}, {"1"=>{:name=>"Renny's Diggin'", :race_no=>"2", :drawn_box=>"3"}}, {"3"=>{:name=>"Fernando Hill", :race_no=>"2", :drawn_box=>"4"}}, {"2"=>{:name=>"Timely Fashion", :race_no=>"2", :drawn_box=>"6"}}, {"1"=>{:name=>"Federal Fletch", :race_no=>"2", :drawn_box=>"9"}}, {"2"=>{:name=>"Awesome Buddy", :race_no=>"4", :drawn_box=>"3"}}, {"7"=>{:name=>"Zipping Annabel", :race_no=>"4", :drawn_box=>"4"}}, {"4"=>{:name=>"Kylie Keeping", :race_no=>"4", :drawn_box=>"8"}}, {"5"=>{:name=>"Stent", :race_no=>"4", :drawn_box=>"1"}}, {"5"=>{:name=>"Jabeni", :race_no=>"4", :drawn_box=>"2"}}, {"11"=>{:name=>"Barsandi", :race_no=>"4", :drawn_box=>"6"}}, {"1"=>{:name=>"Little Prayer", :race_no=>"6", :drawn_box=>"2"}}, {"2"=>{:name=>"Charming Spirit", :race_no=>"6", :drawn_box=>"7"}}, {"4"=>{:name=>"Cawbourne Cooper", :race_no=>"6", :drawn_box=>"10"}}, {"2"=>{:name=>"Lagoon Alaska", :race_no=>"6", :drawn_box=>"4"}}, {"1"=>{:name=>"Bella Nineteen", :race_no=>"6", :drawn_box=>"5"}}, {"4"=>{:name=>"Annie Rocks", :race_no=>"6", :drawn_box=>"9"}}, {"1"=>{:name=>"Regent Tree", :race_no=>"8", :drawn_box=>"2"}}, {"1"=>{:name=>"Laughing Boy", :race_no=>"8", :drawn_box=>"7"}}, {"2"=>{:name=>"Smiley", :race_no=>"8", :drawn_box=>"8"}}, {"1"=>{:name=>"Sentosa Doll", :race_no=>"8", :drawn_box=>"9"}}, {"1"=>{:name=>"Propagandist", :race_no=>"8", :drawn_box=>"10"}}, {"2"=>{:name=>"Sakeyna", :race_no=>"3", :drawn_box=>"7"}}, {"2"=>{:name=>"King Kinloch", :race_no=>"3", :drawn_box=>"8"}}, {"2"=>{:name=>"Zipping Sherman", :race_no=>"3", :drawn_box=>"10"}}, {"3"=>{:name=>"Hard Case Watson", :race_no=>"3", :drawn_box=>"1"}}, {"3"=>{:name=>"Star Connie", :race_no=>"3", :drawn_box=>"2"}}, {"4"=>{:name=>"Ultimate Display", :race_no=>"3", :drawn_box=>"3"}}, {"5"=>{:name=>"Miss Milwaukee", :race_no=>"3", :drawn_box=>"5"}}, {"7"=>{:name=>"Duck And Dive", :race_no=>"3", :drawn_box=>"6"}}, {"1"=>{:name=>"Sentosa Doll", :race_no=>"3", :drawn_box=>"9"}}, {"2"=>{:name=>"My Sienna", :race_no=>"5", :drawn_box=>"1"}}, {"2"=>{:name=>"Simply Patches", :race_no=>"5", :drawn_box=>"6"}}, {"2"=>{:name=>"Sooky Lala", :race_no=>"5", :drawn_box=>"8"}}, {"3"=>{:name=>"Tiggerlong Pink", :race_no=>"5", :drawn_box=>"10"}}, {"5"=>{:name=>"Outside World", :race_no=>"5", :drawn_box=>"2"}}, {"1"=>{:name=>"Go Forward Bruno", :race_no=>"5", :drawn_box=>"3"}}, {"6"=>{:name=>"Zipping Anthea", :race_no=>"5", :drawn_box=>"5"}}, {"5"=>{:name=>"Simply Houdini", :race_no=>"5", :drawn_box=>"7"}}, {"3"=>{:name=>"Beauty's Girl", :race_no=>"5", :drawn_box=>"9"}}, {"3"=>{:name=>"Ziggy Stardust", :race_no=>"7", :drawn_box=>"1"}}, {"7"=>{:name=>"Flashing Oscar", :race_no=>"7", :drawn_box=>"2"}}, {"5"=>{:name=>"Kurios Motion", :race_no=>"7", :drawn_box=>"3"}}, {"7"=>{:name=>"Kermaro", :race_no=>"7", :drawn_box=>"4"}}, {"6"=>{:name=>"Tap Out Lucy", :race_no=>"7", :drawn_box=>"5"}}, {"10"=>{:name=>"Zipping Benson", :race_no=>"7", :drawn_box=>"6"}}, {"24"=>{:name=>"Fire Legend", :race_no=>"7", :drawn_box=>"7"}}, {"8"=>{:name=>"Dashing Display", :race_no=>"7", :drawn_box=>"8"}}, {"2"=>{:name=>"Rattlin' Home", :race_no=>"9", :drawn_box=>"1"}}, {"3"=>{:name=>"Byron Breeze", :race_no=>"9", :drawn_box=>"3"}}, {"5"=>{:name=>"Shafted", :race_no=>"9", :drawn_box=>"4"}}, {"8"=>{:name=>"Eva's Girl", :race_no=>"9", :drawn_box=>"5"}}, {"6"=>{:name=>"Blazin' Sophia", :race_no=>"9", :drawn_box=>"6"}}, {"7"=>{:name=>"Enjoy Yourself", :race_no=>"9", :drawn_box=>"7"}}, {"3"=>{:name=>"General George", :race_no=>"9", :drawn_box=>"8"}}, {"2"=>{:name=>"Zipping Sherman", :race_no=>"9", :drawn_box=>"9"}}, {"1"=>{:name=>"Teeny Tiger", :race_no=>"10", :drawn_box=>"4"}}, {"2"=>{:name=>"Tiggerlong Blaze", :race_no=>"10", :drawn_box=>"7"}}, {"1"=>{:name=>"Propagandist", :race_no=>"10", :drawn_box=>"9"}}, {"1"=>{:name=>"Sentosa Doll", :race_no=>"10", :drawn_box=>"10"}}, {"1"=>{:name=>"Fascinate Hannah", :race_no=>"10", :drawn_box=>"1"}}, {"4"=>{:name=>"Olivia's Chance", :race_no=>"10", :drawn_box=>"2"}}, {"2"=>{:name=>"Prelious Jade", :race_no=>"10", :drawn_box=>"3"}}, {"1"=>{:name=>"Still Laughing", :race_no=>"10", :drawn_box=>"5"}}]

want to group with the key example: {"1"=> , "2"=> etc..

I have tried this

wins.group_by { |h| h.keys.first }.sort.reverse.to_h

I am getting the result like

{"8"=>[{"8"=>{:name=>"Dashing Display", :race_no=>"7", :drawn_box=>"8"}}, {"8"=>{:name=>"Eva's Girl", :race_no=>"9", :drawn_box=>"5"}}], "7"=

but I need a response like

{"8"=>[{:name=>"Dashing Display", :race_no=>"7", :drawn_box=>"8"}, {:name=>"Eva's Girl", :race_no=>"9", :drawn_box=>"5"}], etc ...

How can I get the expected response?

Upvotes: 3

Views: 1449

Answers (3)

max pleaner
max pleaner

Reputation: 26788

So if we take your current result:

result1 = wins.group_by { |h| h.keys.first }.sort.reverse.to_h

Now the keys are strings like "8", and the values are lists of hashes.

All we want to do here is take those lists of hashes, and for each of them, simply extract the first value, because we know they each only have one value.

To do this:

result2 = result1.transform_values do |list_of_hashes|
  list_of_hashes.map { |hash| hash.values.first }
end

Another approach would be to just process the whole thing with reduce:

result = wins.reduce({}) do |memo, hash|
  key = hash.keys.first
  memo[key] ||= []
  memo[key].push hash.values.first
  memo
end.sort.reverse

Upvotes: 1

Cary Swoveland
Cary Swoveland

Reputation: 110755

If arr is the array of hashes given in the question's example, one can write the following:

f = arr.each_with_object(Hash.new { |h,k| h[k] = [] }) do |g,h|
  k,f = g.flatten
  h[k] << f
end

When, for example,

g = {"8"=>{:name=>"Dashing Display", :race_no=>"7", :drawn_box=>"8"}}

k,f = g.flatten
  #=> ["8", {:name=>"Dashing Display", :race_no=>"7", :drawn_box=>"8"}]
k #=> "8" 
f #=> {:name=>"Dashing Display", :race_no=>"7", :drawn_box=>"8"}

See Hash#flatten.

I assume the order of the keys in the hash that is returned is unimportant. I further assume that the order of the hashes in the arrays that are the values of those keys is also unimportant.

This uses the form of Hash::new that has a block but no argument. When h has no key k this causes h[k] = [] to be executed immediately before h[k] << f is executed.

We find, for example:

f['8']
  #=> [{:name=>"Dashing Display", :race_no=>"7", :drawn_box=>"8"},
  #    {:name=>"Eva's Girl", :race_no=>"9", :drawn_box=>"5"}]

The corresponding elements (hashes) of arr that have a key '8' are as follows:

arr.select { |h| h.keys == ["8"] }
  #=> [{"8"=>{:name=>"Dashing Display", :race_no=>"7", :drawn_box=>"8"}},
  #    {"8"=>{:name=>"Eva's Girl", :race_no=>"9", :drawn_box=>"5"}}]

​ The calculation of f is seen to produce the desired result.

Upvotes: 3

Nitin Singh
Nitin Singh

Reputation: 11

you can write your own custom logic to achieve above grouping. Something like below:

result = {}
input.each do |element|
  key = element.keys.first
  result.merge!(key => (result[key] || []) << element[key])
end
result

And later on sort this based on your requirement.

Upvotes: 1

Related Questions