aprogrammer
aprogrammer

Reputation: 45

Find all max values in an array of hashes and then store in a separate array Ruby

I am new to programming and am using Ruby to get familiar with syntax and control flow.

The program I am working on wants me to puts the dvd name that has the longest playing time. Here is my code:

dvds = [
  {
    :dvd_name=>"x-men",
    :dvd_playing_time=>549,
    :times_played=>9.0
  },
  {
    :dvd_name=>"Pi",
    :dvd_playing_time=>549,
    :times_played=>6.0
  }
]

Both hashes have dvd_playing_time of 549, so I want both "x-men" and "Pi" stored in an array. I tried max_by, but it only returns one dvd_name.

dvds.max_by { |length| length[:dvd_playing_time]}[:dvd_name]

Any help you can provide is fantastic!

Upvotes: 0

Views: 136

Answers (2)

eiko
eiko

Reputation: 5345

If you want to do it in one line:

dvds.group_by{ |dvd| dvd[:dvd_playing_time] }.max.last.map{ |dvd| dvd[:dvd_name] }

This code groups the dvds by length, takes the group with the max length, and maps it to only contain the dvd names. It's not the fastest option since it'll run through the array a few times (n + g + m times, technically).

If you're concerned about speed:

max = 0
longest = []
dvds.each do |dvd|
  if dvd[:dvd_playing_time] > max
    max = dvd[:dvd_playing_time]
    longest = [dvd[:dvd_name]]
  elsif dvd[:dvd_playing_time] == max
    longest << dvd[:dvd_name]
  end
end

This algorithm, while inelegant, will give you the answer with a single iteration through the array, which is the best you can do.

Upvotes: 1

Cary Swoveland
Cary Swoveland

Reputation: 110675

There are three steps to get an answer.

  • Determine the longest playing time, by Enumerable#maping each hash h to h[:dvd_length] and then taking the Enumerable#max of those values.
  • Use Hash#select to select the hashes h for which h[:dvd_length] equals that maximum playing time.
  • Enumerable#map those hashes h with the maximum playing time to h[:dvd_name].

length_of_longest = dvds.map { |h| h[:dvd_length] }.max
  #=> 549
puts dvds.select { |h| h[:dvd_length] == length_of_longest }.map { |h| h[:dvd_name] }
  # x-men
  # Pi

Upvotes: 3

Related Questions