I have the below data structure in Ruby:
people = [
{ "name" => "John", "hobby" => "tennis", "food" => "pizza" },
{ "name" => "Joseph", "hobby" => "tennis", "food" => "burgers" },
{ "name" => "Lauren", "hobby" => "board games", "food" => "salads" }
{ "name" => "Amir", "hobby" => "cycling", "food" => "burgers" },
{ "name" => "Mary", "hobby" => "tennis", "food" => "salads" },
{ "name" => "Karen", "hobby" => "board games", "food" => "pie" },
{ "name" => "Will", "hobby" => "cycling", "food" => "pizza" },
]
I need to write a program that will take in user input - either "hobby" or "food" and will then puts out a list of people grouped under subheadings for each hobby or food.
e.g. user inputs 'hobby' and a list is puts'ed to the console similar to the below:
tennis John Joseph Mary board games Lauren Karen cycling Amir Will
So far I have got as far as being able to generate a new array that has the hobbies and the names, however they are seperate and I'm not sure if it's the best way of going around getting the category name with a list of people underneath... also there are a few nil values being pulled out too e.g. below:
puts "Enter what category to search"
category = gets.chomp
grouped_data = people.group_by { |x| x[category] }
new_array = []
grouped_data.each { |n| new_array.push n[0] }
grouped_data.flatten.flatten.each { |n| new_array.push n["name"] }
p new_array
With input "hobby" gives me an array:
["tennis", "board games", "cycling", nil, "John", "Joseph", "Mary", nil, "Lauren", "Karen", nil, "Amir", "Will"]
Am I on the right track? Is there another avenue worth exploring?
Thanks! Hope this has been laid out alright as it's first time posting on SA.
CodePudding user response:
A little more directly, grouping by hobby without creating unnecessary intermediate objects.
by_hobbies = people.each_with_object({}) do |person, hsh|
hobby = person["hobby"]
hsh[hobby] ||= []
hsh[hobby] << person["name"]
end
p by_hobbies
Output:
{"tennis"=>["John", "Joseph", "Mary"], "board games"=>["Lauren", "Karen"], "cycling"=>["Amir", "Will"]}
CodePudding user response:
I think you are on the right track by using Enumerable#group_by since it gets you a hash where the keys are the "category" and the values are an array of "persons" that fit that "category". What I think you want to do next is use Hash#transform_values along with Array#map to map each person into just thier name.
people = [
{ "name" => "John", "hobby" => "tennis", "food" => "pizza" },
{ "name" => "Joseph", "hobby" => "tennis", "food" => "burgers" },
{ "name" => "Lauren", "hobby" => "board games", "food" => "salads" } ,
{ "name" => "Amir", "hobby" => "cycling", "food" => "burgers" },
{ "name" => "Mary", "hobby" => "tennis", "food" => "salads" },
{ "name" => "Karen", "hobby" => "board games", "food" => "pie" },
{ "name" => "Will", "hobby" => "cycling", "food" => "pizza" },
]
by_category = people.group_by {|category| category["hobby"]}
.transform_values {|value| value.map{ |person| person["name"]}}
p by_category
Which produces:
{"tennis"=>["John", "Joseph", "Mary"], "board games"=>["Lauren", "Karen"], "cycling"=>["Amir", "Will"]}