Home > Blockchain >  Grouping individuals by hash values in an array of hashes from user input and outputting names in Ru
Grouping individuals by hash values in an array of hashes from user input and outputting names in Ru

Time:11-13

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"]}
  •  Tags:  
  • ruby
  • Related