Danny
Danny

Reputation: 19

ruby hash searching for two criterias

grades = [
  {:student=>"James", :age=>19, :score=>85},
  {:student=>"Kate", :age=>19, :score=>92},
  {:student=>"Sara", :age=>20, :score=>74},
  {:student=>"Riley", :age=>20, :score=>85},
  {:student=>"patrick", :age=>20, :score=>96},
  {:student=>"luke", :age=>21, :score=>88},
  {:student=>"susie", :age=>21, :score=>90}
]

I am trying to get the student with the highest score that is the age 20 but only can sort the highest by all the students. Does any one know how to limit the max_by to only students that are 20 from the above hash ?

Upvotes: 1

Views: 62

Answers (3)

mechnicov
mechnicov

Reputation: 15298

Just as idea.

Suppose we have several 20-year-old students with the same maximum score.

In this case variants of Cary and Ursus return only first person.

Therefore, such a thought occurred to me:

grades = [
  {:student=>"James", :age=>19, :score=>85},
  {:student=>"Kate", :age=>19, :score=>92},
  {:student=>"Sara", :age=>20, :score=>74},
  {:student=>"Riley", :age=>20, :score=>85},
  {:student=>"Patrick", :age=>20, :score=>96},
  {:student=>"Vladimir", :age=>20, :score=>96},
  {:student=>"Luke", :age=>21, :score=>88},
  {:student=>"Susie", :age=>21, :score=>90}
]

def best20(grades)
  students20 = grades.select { |r| r[:age] == 20 }
  return nil if students20.empty?
  max_score20 = students20.max_by { |r| r[:score] }[:score]
  students20.select { |r| r[:score] == max_score20 }.map { |r| r[:student] }
end

best20 grades
# => ["Patrick", "Vladimir"]

best20 [{:student=>"James", :age=>19, :score=>85}]
# => nil

Do not judge strictly, this is just an idea.

Upvotes: 0

Cary Swoveland
Cary Swoveland

Reputation: 110725

My objective is to make a single pass through the hashes.

Initially I posted the following, but it was incorrect because it returns the name of a student who is not 20 if there are no students of age 20.

grades.max { |h| h[:age] == 20 ? h[:score] :
  -Float::INFINITY }[:student]

Here is my revised answer:

def best20(grades)
  student = nil
  highest = -Float::INFINITY
  grades.each do |h|
    if h[:age] == 20 && h[:score] > highest
      highest = h[:score]
      student = h[:student]
    end
  end
  student
end

best20 grades
  #=> "patrick"

best20 [{:student=>"James", :age=>19, :score=>85}]
  #=> nil

Upvotes: 1

Ursus
Ursus

Reputation: 30071

  1. filter for people with age 20
  2. find the maximum score

    grades.select { |person| person[:age] == 20 }.max_by { |person| person[:score] }
    

Upvotes: 4

Related Questions